__attribute__
是一个编译器指令,实际上是GNU C的一种机制。它本质上是一个编译器指令,可以在声明变量、函数、参数、方法、类等时提供一些属性,这些属性在编译阶段起作用,用于进行多样化的错误检查和高级优化。
合理使用**__attribute__
**有什么好处呢?
首先,它可以给编译器提供上下文,帮助编译器进行优化。通过合理使用**__attribute__
,可以显著提高优化效果。其次,编译器会基于__attribute__
产生一些编译警告,从而使代码更加规范。此外,__attribute__
**还可以为代码阅读者提供必要的注解,帮助他们理解代码意图。
总之,**__attribute__
的作用是为编译器提供上下文。然而,如果错误地使用__attribute__
**指令,就可能给编译器提供错误的上下文,引发难以发现的错误。
强符号和弱符号
许多C语言学习者都认为,在同一作用域下不能定义相同的变量或函数。然而,这种观点是偏颇的。GNU C对标准C语言进行了扩展,在GCC中,符号(变量和函数在编译时被抽象成符号)可以分为强符号和弱符号。需要注意的是,是否支持这个特性取决于不同的C语言标准。
对于C/C++来说,默认情况下,编译器将函数和已初始化的全局变量视为强符号,而将未初始化的全局变量视为弱符号。当开发者没有明确指定时,编译器对强符号和弱符号的定义具有一些默认行为。同时,开发者也可以使用”attribute((weak))”来声明一个符号为弱符号。
当定义了相同的变量时,如果其中一个是强符号,另一个是弱符号,GCC在编译时不会报错,而是根据一定的规则进行取舍:
-
如果两个符号都是强符号,会报错:redefinition of ‘xxx’ -
如果一个是强符号,一个是弱符号,会选择强符号的值 -
如果两个符号都是弱符号,会选择占用空间较大的符号。这个规则比较好理解,编译器无法确定开发者的意图,选择占用空间较大的符号可以避免诸如溢出、越界等严重后果。 -
在默认的符号类型情况下,强符号和弱符号可以共存,就像下面的示例一样:
int x;
int x = 1;
编译不会报错,在编译时x的取值将会是1.
但是使用 __attribute__((weak))
将强符号转换为弱符号,却不能与一个强符号共存,类似于这样:
int __attribute__((weak)) x = 0;
int x = 1;
编译器将报重复定义错误。
强引用和弱引用
除了强符号和弱符号的区别之外,GNUC还有一个特性就是强引用和弱引用,我们知道的是,编译器在编译阶段只负责将源文件编译成目标文件(即二进制文件),然后由链接器对所有二进制文件进行链接操作。
在分离式编译中,当编译器检查到当前使用的函数或者变量在本模块中仅有声明而没有定义时,编译器直接使用这个符号,将工作转交给链接器,链接器则负责根据这些信息找到这些函数或者变量的实体地址。
因为在程序执行时,程序必须确切地知道每个函数和全局变量的地址。如果没有找到该符号的实体,就会报undefined reference错误,这种符号之间的引用被称为强引用.
编译器默认所有的变量和函数为强引用,同时编程者可以使用 __attribute__((weakref))
来声明一个函数,注意这里是声明而不是定义,既然是引用,那么就是使用其他模块中定义的实体,对于函数而言,我们可以使用这样的写法:
__attribute__((weakref)) void func(void);
然后在函数中调用func(),如果func()没有被定义,则func的值为0,如果func被定义,则调用相应func,在《程序员的自我修养》这本书中有介绍,它是这样写的:
__attribute__((weakref)) void func(void);
void main(void)
{
if(func) {func();}
}
但是在现代的编译系统中,这种写法却是错误的,编译虽然通过(有警告信息),但是却不正确:
warning: ‘weakref’ attribute should be accompanied with an ‘alias’ attribute [-Wattributes]
警告显示:weakref需要伴随着一个别名才能正常使用
强/弱符号和强/弱引用的作用
这种弱符号、弱引用的扩展机制在库的实现中非常有用。我们在库中可以使用弱符号和弱引用机制,这样对于一个弱符号函数而言,用户可以自定义扩展功能的函数来覆盖这个弱符号函数。
同时我们可以将某些扩展功能函数定义为弱引用,当用户需要使用扩展功能时,就对其进行定义,链接到程序当中,如果用户不进行定义,则链接也不会报错,这使得库的功能可以很方便地进行裁剪和组合。
注意:C标准里根本没有提到强、弱符号。这只是GCC这个实现定义的特性,在MS C编译器里是不存在这个概念的。
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !