最近查看linux内核代码时,表现了一些编译器选项如__attribute_((weak))、__attribute__( (alias("target"))),一开始不了解,后来本身查看资料及书籍算是对gcc的这个编译属性有了必定的认识。
1、先了解weak属性。
__attribute__((weak))表示为弱符号属性,所谓的弱符号是针对于强符号来讲的,咱们定义的全局已初始化变量及全局函数等都是属于强符号,在连接时若是有多个强符号就会报错误;而弱符号主要指未初始化的全局变量或经过__attribute__((weak))来显式申明的变量或函数。
html
/* file:weak_test.c */ void weak_func_test(void) __attribute__((weak)); /* 显式申明为weak,属于弱符号(函数) */ int weak_var_test; /* 未初始化的全局变量,属于弱符号 */ #ifdef WEAK_SYM void weak_func_test(void) {
printf("%s:%s.c in\n", __FILE__, __func__); } #endif int main() { printf("weak_var_test:%d\n", weak_var_test); weak_func_test(); return 0; } /* file:symbol.c */ int weak_var_test = 6666; /* 已初始化的全局变量,属于强符号 */ /* 全局函数属于强符号 */ void weak_func_test(void) { printf("%s:%s() in\n", __FILE__, __func__); }
一、使用编译命令gcc weak_test.c symbol.c DWEAK_SYM -o weak_test,执行./weak_test,打印weak_var_test为6666,函数weak_func_test()打印symblo.c:weak_func_test() in(注意是symbol.c的函数),从执行结果看symbol.c的weak_var_test及weak_func_test覆盖了weak_test.c的符号,说明连接时强弱符号都存在时以强符号为准;
二、再使用编译命令而gcc weak_test.c -DWEAK_SYM -o weak_test,执行./weak_test,打印weak_var_test为0(未初始化的全局变量编译器默认为0),函数执行打印weak_test.c:weak_func_test() in(这时是weak_test.c的函数),说明链接时若是只有弱符号时以弱符号为准。
三、继续编译gcc weak_test.c -o weak_test,这时可能你们会有疑问,weak_func_test函数没有实现,那么连接的时候应该会报错吧;实际上确定是不会的,就是由于咱们 将这个函数显式的申明为weak symbol,申明为weak symbol的函数在.o目标文件里面是以WEAK及UND形式存在的,符号的地址为0,具体能够用readelf -s 命令查看。
那么这种状况下只有弱符号weak_func_test存在,最终连接时也以弱符号为准,只不过此函数的地址为0,因此这时咱们去执行./weak_test的时候必然会有segement fault的错误产生,就是由于去访问了null指针。
四、弱符号还有一个规则,就是两个都是弱符号时,之内存占用大小较大的那个符号为准。好比未初始化的char var和long var同时存在时,连接器以实际sizeof(long)的大小来给var分配空间,实例就不讲述了,碰见这种状况须要额外当心。
小结:weak属性基本已讲述完成,其实弱符号在实际中也有不少应用。好比说在一个库里面实现某个函数,申明为弱符号,在某种状况下咱们能够用本身的代码去覆盖库的实现从而从新去实现某个函数,达到定制化的目的。
2、接下去讲述alias属性,alias属性比较简单,从字面意思理解就是给符号设置一个别名,至关于取一个外号。使用方法以下:
void func(void);
void alias_func(void) __attribute__((alias("func"))); 须要注意c++的符号修饰机制!
这样的意思就是函数func的别名或外号是alias_func,那么就是调用alias_func()和func()的效果是同样的,有兴趣的话能够本身写代码验证。这时须要主意func函数必须是要有定义的,不然会编译报错的。
linux
3、最后还有一个属性是weakref活weakref("target")
__attribute__((weakref))为弱引用,请注意引用与定义的区别。weakref就是申明某个引用为弱引用,弱引用时若是需引用符号不存在也不会连接出错,而是将须要引用的符号定义为WEAK属性及0地址(跟前面的WEAK属性很类似吧)。
weakref的用法有点特别,必需要配合alias使用及必须是static定义。__attribute__((weak("target")))至关于__attribute__((weakref,alias("target"))),如下看个实例:
c++
/* ** weakref_test.c */ /* 申明func_alias函数func的带弱引用的别名 */ void func(void) { printf("func:%s in\n", __FUNC__); }
static void func_alias(void) __attribute__((weakref,alias("func"))); int main() { func_alias(); /* 至关于调用func */ return 0; }