既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
对于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需要伴随着一个别名才能正常使用
强/弱符号和强/弱引用的作用
这种弱符号、弱引用的扩展机制在库的实现中非常有用。
我们在库中可以使用弱符号和弱引用机制,这样对于一个弱符号函数而言,用户可以自定义扩展功能的函数来覆盖这个弱符号函数。
同时我们可以将某些扩展功能函数定义为弱引用,当用户需要使用扩展功能时,就对其进行定义,链接到程序当中。
如果用户不进行定义,则链接也不会报错,这使得库的功能可以很方便地进行裁剪和组合。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**