gcc的一些扩展:
预定义的一些宏?
__FILE__
__LINE__
__DATE__
__TIME__
__FUNCTION__
#pragma pack(n) 字节对齐,默认4字节对齐,64位系统8字节对齐性能更高一些
gcc特有__attribute__ ((属性)) 修饰函数或者变量
如何在main函数之前执行一个函数?
void functionA()__attribute__((constructor)); // run before main()
void functionB()__attribute__((destructor)); //run after main()
结构体的对齐 aligned(n), 取代#pragma pack(n) ?
typedef struct A{
char a;
double b;
char c;
} A;
printf("sizeof A = %d\n", sizeof(A));//猜猜结果, 默认4字节对齐,一般来说不是 1+ 8+1=10,而是 4+ 8+4,知道为什么吗?
typedef struct B{
char a;
double b;
char c;
}__attribute__((aligned(1))) B;
printf("sizeof B = %d\n", sizeof(B));//猜猜结果, 这次就是1+8+1=10了,自己试试,果真这样吗
如果把aligned(1) 换成packed
typeof 的使用?
int a;
typeof(a) 就是int,这是编译期间的行为, 尤其用在消除宏的副作用上
一些命令:
nm 输出库或可执行文件的符号
ldconfig 把动态库放到缓存中去,系统启动自动执行,如果你安装了动态库,重启系统,可不用理会
ldd 查看一个可执行文件依赖哪些动态库. 输出 so的列表
ln 建立符号链接 ln -s aaa.so.6 aaa.so
wc -l 统计行数 -w统计单词数 -c 统计字符数
wc -l main.c 统计代码行数,从文件接受输入
env | wc -l 接受管道的输入
wc -l 从标准输入接受输入
size a.out 显示一个程序运行的内存大小
加载动态库:
#include<dlfcn.h> //dynamic load function
编译时候链接库libdl.so 选项 -ldl
void* dlopen(char* filename, int flag);//失败返回NULL, flag是懒加载还是立刻加载RTLD_LAZY RTLD_NOW (RTLD :runtime load)
char* dlerror();//可以用获取加载失败的原因,会清掉错误信息并返回NULL
void* dlsym(void* handle, char* symbol);//取得符号地址,失败返回NULL(严格的做法是先调用dlerror()清除错误信息,
再调用其他操作dlsym(),如果在调用dlerror()返回NULL则说明没错误) ,拿到地址就能调用函数,访问内存变量
int dlclose(void* handle);//关闭动态库,从内存中卸载
需要注意的是,如果dlopen打开库文件的时候没有指定路径,那么就会去/lib 或/usr/lib下去寻找库文件
访问环境变量?
命令行 env / set
程序中 int main(int argc, char** argv, char* env[ ]);// 注意潜规则,最后一个item是NULL
#include<stdlib.h>
char* getenv(char *key); // getenv("path")
int putenv(char* string);//返回成功和失败,0 表示成功 -1表示失败 例如path:kjdflsfj; dfdsfdsfsd; dfdsfsd;
int setenv(char* key, char* value,int override);// 0成功,-1失败, override是否覆盖
int unsetenv(char* key);//取消某个环境变量
int clearenv();//清除所有环境变量
注意:以上对环境变量的操作只影响当前进程,
进程的内存独立性?
每个进程都拥有独立4G的内存空间,但并不是真正有4G的实际物理内存
操作系统为每个进程建立虚拟地址映射表,以页为单位进行映射
所以,两个进程,同一个虚拟地址,但是访问不同的物理地址
不分页,虚拟地址就是物理地址,分页后就不确定了
因此,指针跨越进程就毫无意义。
#include<unistd.h>
int getpagesize();//返回页的大小
进程内存分段:
代码段(函数和常量)
数据段(带初始化的全局变量和初始化的静态局部变量)
BSS段 (未初始化的全局变量和未初始化的静态局部变量)
堆 (动态分配的内存)
栈(普通的局部变量)
低级的内存分配:
C使用malloc realloc calloc分配内存,两次分配的内存一定不连续
#include<unistd.h>
重新指定数据段的结束位置
int brk(void *addr);//重新指定结束地址
void *sbrk(intptr_t increment);//增量可正可负或0