GCC中的“重定义”—— weak

最近玩STM32,里面有个关键字 __weak,当我们重定义了用__weak修饰的函数时,运行过程中会调用我们重定义的函数。

image

这和C++中的重定义有异曲同工之妙,并且与《程序员的自我修养》书中介绍的弱符号类似。

弱符号与强符号

  • 1、 C/C++中,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号
  • 2、自定义将强符号变为弱符号: __attribute__((weak))

规则1:不允许强符号被多次定义
规则2:如果一个符号在某个目标文件中是强符号,在其他文件中都是弱符号,那么选择强符号
规则3:如果一个符号在所有目标文件中都是弱符号,那么选择其中占用空间最大的一个

// 不是强符号也不是弱符号,是外部变量引用
extern int ext;

// 弱符号
int weak;

// 强符号
int strong = 1;

// 弱符号(这种转化为弱符号的变量不能与全局变量:`int weak2 = 1;` 共存)
int __attribute__((weak)) weak2 = 2;

// 强符号
int main()
{
    return 0;
}

弱引用和强引用

  • 未找到强引用符号的定义,链接器报错:符号未定义
  • 弱引用符号未定义不报错,链接器默认其为0,或一个特殊值。容易运行报错
// 当main函数试图调用foo函数时,foo函数地址为0,发生非法地址访问错误
__attribute__((weakref)) void foo();
int main()
{
    foo();
}

// 改进方法
__attribute__((weakref)) void foo();
int main()
{
    if(foo) foo();
}
  • 库中定义的弱符号可以被用户定义的强符号所覆盖,从而使得程序可以使用自定义版本的库函数
  • 程序可以对某些扩展功能模块的引用定义为弱引用,当我们将扩展模块与程序链接在一起时,功能模块就可以正常使用
  • 如果我们去掉了某些功能模块,那么程序也可以正常链接,只是缺少了相应的功能,使得程序的功能更加容易裁剪和组合

书上案例

Linux程序的设计中,如果一个程序被设计成可以支持单线程或多线程的模式,就可以通过弱引用的方法来判断当前的程序是链接到了单线程的Glibc库还是多线程的Glibc库(是否在编译时有-lpthread选项),从而执行单线程版本的程序或多线程版本的程序。我们可以在程序中定义一个pthread_create函数的弱引用,然后程序在运行时动态判断是否链接到pthread库从而决定执行多线程版本还是单线程版本

image

posted @ 2023-06-08 08:24  Qing-Huan  阅读(222)  评论(0编辑  收藏  举报