Linux C 整理-1

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














猜你喜欢

转载自blog.csdn.net/mtaxot/article/details/72854524