linux 弱符号,强符号和弱符号

本文详细解释了C语言中符号重复定义的问题,介绍了强符号和弱符号的概念,以及链接器处理这两种符号的规则。通过实例展示了如何使用`__attribute__((weak))`定义弱符号,并探讨了弱符号在库开发中的应用,强调了避免不同类型的弱符号定义以减少错误的重要性。
摘要由CSDN通过智能技术生成

我们在编写代码的过程中经常会遇到一种叫做符号重复定义(Multiple Definition)的错误,这是因为在多个源文件中定义了名字相同的全局变量,并且都将它们初始化了。

例如,在 a.c 中定义了全局变量 global:

~~~

int global = 10;

~~~

在 b.c 中又对 global 进行了定义:

~~~

int global = 20;

~~~

那么在链接时就会出现下面的错误:

~~~

b.o: multiple definition of `global'

a.o: first defined here

~~~

这种符号的定义可以被称为强符号。

在C语言中,编译器默认函数和初始化了的全局变量为强符号(Strong Symbol),未初始化的全局变量为弱符号(Weak Symbol)。强符号之所以强,是因为它们拥有确切的数据,变量有值,函数有函数体;弱符号之所以弱,是因为它们还未被初始化,没有确切的数据。

链接器会按照如下的规则处理被多次定义的强符号和弱符号:

1. 不允许强符号被多次定义,也即不同的目标文件中不能有同名的强符号;如果有多个强符号,那么链接器会报符号重复定义错误。

2. 如果一个符号在某个目标文件中是强符号,在其他文件中是弱符号,那么选择强符号。

3. 如果一个符号在所有的目标文件中都是弱符号,那么选择其中占用空间最大的一个。

比如目标文件 a.o 定义全局变量 global 为 int 类型,占用4个字节,目标文件 b.o 定义 global 为 double 类型,占用8个字节,那么被链接后,符号 global 占用8个字节。请尽量不要使用多个不同类型的弱符号,否则有时候很难发现程序错误。

在 GCC 中,可以通过`__attribute__((weak))`来强制定义任何一个符号为弱符号。假设现在有下面的一段代码:

~~~

extern int ext;

int weak1;

int strong = 100;

__attribute__((weak)) weak2 = 2;

int main(){

return 0;

}

~~~

weak1 和 weak2 是弱符号,strong 和 main 是强符号,而 ext 既非强符号也非弱符号,它是一个对外部变量的引用(使用)。

为了加深理解,我们不妨再来看一个多文件编程的例子。

main.c 源码:

~~~

#include

//弱符号

__attribute__((weak)) int a = 20;

__attribute__((weak)) void func(){

printf("C Language\n");

}

int main(){

printf("a = %d\n", a);

func();

return 0;

}

~~~

module.c 源码:

~~~

#include

//强符号

int a = 9999;

void func(){

printf("c.biancheng.net\n");

}

~~~

在 GCC 中,使用下面的命令来运行程序:

~~~

$gcc main.c module.c

$./a.out

a = 9999

c.biancheng.net

~~~

在 main.c 中,a 和 func 都是弱符号,在 module.c 中,a 和 func 都是强符号,强符号会覆盖弱符号,所以链接器最终会使用 module.c 中的符号,输出结果也印证了这一点。

需要注意的是,`__attribute__((weak))`只对链接器有效,对编译器不起作用,编译器不区分强符号和弱符号,只要在一个源文件中定义两个相同的符号,不管它们是强是弱,都会报“重复定义”错误。请看下面代码:

~~~

#include

__attribute__((weak)) int a = 20;

int a = 9999;

int main(){

printf("a = %d\n", a);

return 0;

}

~~~

这段代码在编译阶段就会报错,编译器会认为变量 a 被定义了两次,属于重复定义。

弱符号对于库来说十分有用,我们在开发库时,可以将某些符号定义为弱符号,这样就能够被用户定义的强符号覆盖,从而使得程序可以使用自定义版本的函数,增加了很大的灵活性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值