gcc扩展__attribute__((constructor))详解和在.a库中的使用方法

gcc对c语言做了很多扩展,使得c语言的表现力得到了很大的增强,本文主要介绍一下constructor扩展,这个扩展和C++的构造函数很像,它会在main函数之前由程序加载器自动调用,与之相对的是destructor,它会在main函数执行结束或者exit的时候自动调用,由于两个扩展是一对,destructor这里就不介绍了。ANSI C标准还引入了atexit函数,这个是在进程结束的时候自动调用。和destructor也比较相似。  
constructor扩展的用法如下     


```
void func() __attribute__((constructor));                              
```


他有如下规则
- 构造函数先于main函数而执行
- 不同构造函数如果在同一个文件中,则先出现的函数后执行
- 对于不同文件中的构造函数,编译命令中后出现的.c文件的构造函数先执行


利用constructor属性,我们可以定义一些宏来实现模块的自动注册机制。也就是说我们用宏自动构造注册函数,然后把注册函数赋予constructor属性,这样我们在添加新的模块的时候就不需要显示的调用注册函数来,只需要在模块文件内加上一个宏调用即可。例子如下:


```
#define INITIALIZER(f) \
   static void f(void) __attribute__((constructor)); \
   static void f(void)


#define FAP_REGISTER(name)                                              \
  INITIALIZER(fap_register_ ## name) {                                  \
    fileaccess_register_entry(&fa_protocol_ ## name); \
  }
```


然后我们只要在模块内调用`FAP_REGISTER(fs);`即可,这样做的好处是添加新的模块更加方便,代码维护也更简单,那么问题来了,假如我们现在有这样一套注册机制的模块,我们把它编译成.a库集成到现在的应用方案中,应用没有在任何地方调用我们的注册函数,编译出来的结果能正确自动调用注册函数吗?答案是可能会出问题,定义constructor属性的函数会放在elf文件的constructor区域,在链接的时候由于我们的注册函数没被调用,所以编译器很可能做优化,不去链接我们的注册函数,这样elf文件的constructor区域就没有我们的注册函数,自然注册函数就不会自动的调用了,解决办法就是在链接的时候强制把.a里所有的函数都链接到可执行文件中。我们使用-Wl,--whole-archive和 -Wl,--no-whole-archive这两个链接命令来做这件事情。--whole-archive 可以把在其后面出现的静态库包含的函数和变量输出到结果中,--no-whole-archive 则关掉这个特性。你不想把--whole-archive后边所有.a库的函数和变量都链接到输出结果的时候就需要用--no-whole-archive了,这里需要注意的是-wl,--whole-archive 和 --no-whole-archive 是ld专有的命令行参数,gcc 并不认识,要通gcc传递到 ld,需要在他们前面加 -Wl,例子如下:


```
gcc main.o  -lb.a -wl,--whole-archive -lmode_fs.a -wl, --no-whole-archive -lc.a -lz.a -o man 
```
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gcc 中 __attribute__ 是用来声明特殊属性的关键字,常用于指定变量、函数、类型等的特定属性。以下是 __attribute__ 的常用参数、说明和举例: 1. aligned(n) 说明:指定变量的对齐方式,n 为变量的对齐值,必须为 2 的幂次方。 举例:__attribute__((aligned(16))) int a; 2. packed 说明:指定变量或结构体不进行字节对齐,节省内存空间。 举例:__attribute__((packed)) struct myStruct { char a; int b; }; 3. deprecated 说明:标记函数或变量已过时,编译器会给出警告信息。 举例:__attribute__((deprecated)) void old_function(); 4. noreturn 说明:标记函数不会返回,可以用于告诉编译器代码不会继续执行下去。 举例:__attribute__((noreturn)) void error_exit(); 5. format(fmt, arg) 说明:指定函数的参数格式和类型,类似于 printf 函数。 举例:__attribute__((format(printf, 1, 2))) void my_printf(const char *format, ...); 6. unused 说明:标记变量或函数未被使用,编译器会给出警告信息。 举例:__attribute__((unused)) int unused_variable; 7. constructor(priority) 说明:标记函数为构造函数,可以指定优先级,指定的函数会在 main 函数之前自动执行。 举例:__attribute__((constructor(101))) void my_constructor(); 8. destructor(priority) 说明:标记函数为析构函数,可以指定优先级,指定的函数会在 main 函数之后自动执行。 举例:__attribute__((destructor(101))) void my_destructor();

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值