本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。
引言
__attribute__的官方描述是这样的:
The keyword attribute allows you to specify special properties of variables, function parameters, or structure, union, and, in C++, class members. This attribute keyword is followed by an attribute specification enclosed in double parentheses. Some attributes are currently defined generically for variables. Other attributes are defined for variables on particular target systems. Other attributes are available for functions (see Function Attributes), labels (see Label Attributes), enumerators (see Enumerator Attributes), statements (see Statement Attributes), and for types (see Type Attributes). Other front ends might define more attributes (see Extensions to the C++ Language).
其中所谓的special properties
其实在有时候不是锦上添花,而是雪中送炭,没有的话就会gg。第一次直观的感受就是今天遇到的这种情况。
描述
今天遇到了一个复杂的场景,在欢神的指导下了解了一种__attribute__((weak))极其巧妙的用法,当然是迫不得已需要这种trick的做法,一般情况还是不用好。举个例子:
现在加入了一个新功能,称为a,我们需要两个可执行文件,我们称一个是server,一个是client,这两个可执行文件分别有自己的依赖链,假设server依赖 b.o,c.o,d.o,e.o,a.o,client依赖 e.o,f.o,g.o,假如server的e中需要使用新功能a中的一个函数,但是e包含在server和client的共有依赖中,如果把a.o放到client依赖链末尾的话会导致a依赖的一堆东西(b,c中的符号)不存在,所以会报一堆的undefined reference
,此时当然我们可以把所有依赖的东西都加进来,但是非常麻烦。最trick的方法就是在client引用的函数上面搞一个同名的弱符号,类似于这样:
__attribute__((weak)) void test(size_t unused) {
(void)unused; }
然后server调用的时候就会在强弱符号中选择强符号,client就不会链接错误,因为符号存在,虽然是弱符号。如果把这个符号改为强符号的话在编译server的时候就会出现multiple definition of test
。
总结
作为扩展我们还可以学习下__attribute__((weak)) 其他的细节,比如说其他的用处,这里可以参考[1],这样的用法使得我们可以在不清楚引入的模块中是否存在某个函数但又必须使用的情况下程序的行为正常。
[2]中大神详细的讲解了在链接时gcc参数中直接放.o和静态库之间的细微差别,非常高质量的一篇文章,如果有时间的话可以翻译一下,让更多的人看到这篇的文章。
其他
然后把以前看[3]的时候整理的一份古老的笔记贴出来,记录了一些平时可能用的到的__attribute__
。
- access访问控制符,可以控制传入参数的行为,即检测它们所应用的函数或调用者无效的或者不安全的访问,但是好像在我的机器上没用
- always_inline 在这种情况下不能内联将被视为一种错误
- cold 所有的冷函数将会被放置在一个特殊分段中,提高了非冷部分的代码局部性,
- const 在相同的参数调用同一个函数的时候后面会被替换
- constructor destructor constructor (priority) destructor (priority)在main函数之前被调用和exit之后被调用,支持优先级参数
- flatten 如果可能的话,对于带有此属性的函数,该函数内的每个调用都将内联。属性noinline和similar声明的函数不是内联的。
- hot 函数的hot属性用来通知编译器该函数是已编译程序的一个热点。该函数进行了更积极的优化,在许多目标上,它被放置在文本部分的一个特殊分段中,因此所有热门函数都显示在一起,提高了局部性。
- noinline这个函数属性阻止一个函数被考虑内联。如果函数没有副作用,除了内联之外,还有一些优化会导致函数调用被优化掉,尽管函数调用是活动的。为了避免这样的调用被优化掉
- noreturn 一些标准库函数,如abort和exit,不能返回。GCC自动知道这一点。有些程序定义自己的函数,但永不返回。你可以将它们声明为noreturn来告诉编译器这个事实。
- pure 调用除了返回值以外对程序状态没有可观察的影响的函数可能会使其自己进行优化,使用pure属性声明此类函数可以使GCC避免在重复调用具有相同参数值的函数时发出某些调用。
- returns_nonnull 让编译器在知道返回值永远不会为空的基础上优化调用者
- unused 这个附加到函数的属性意味着该函数可能未使用。GCC不会为此函数生成警告。
- weak 强符号变成弱符号
参考: