,赞 17
`__attribute__` 是一个编译器指令,其实是 `GNU C` 的一种机制,本质是一个编译器的指令,在声明的时候可以提供一些属性,在编译阶段起作用,来做多样化的错误检查和高级优化。
用于在 `C`,`C++`,`Objective-C` 中修饰变量、函数、参数、方法、类等。
#### 合理使用 `__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还有一个特性就是强引用和弱引用。
我们知道的是,编译器在编译阶段只负责将源文件编译成目标文件(即二进制文件),然后由链接器对所有二进制文件进行链接操作。
编译器默认所有的变量和函数为强引用,同时编程者可以使用`__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需要伴随着一个别名才能正常使用
**收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。**


**[如果你需要这些资料,可以戳这里获取](https://gitee.com/vip204888)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**
**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**