GNU链接器不再覆盖Weak symbols?多定义错误疑问
关于同名全局变量链接报错的原因及解决方法
首先要纠正一个概念:你代码里的int x;属于tentative definition(暂定定义),并非weak symbol(弱符号)。弱符号需要通过__attribute__((weak))显式声明,两者是完全不同的概念。
为什么现在会报错?
《深入理解计算机系统》(CSAPP)7.6节描述的是C89标准下的传统链接行为:当时C语言允许多个文件中的暂定定义(未初始化的全局变量)被当作common symbol处理,链接器会自动合并这些符号,最终只保留一个实例。
但从C99标准开始,规则发生了变化:暂定定义会被视为regular definition(常规定义)(强符号)。而GCC从较新版本开始(比如你使用的11.3.0),默认采用C99及之后的标准模式,此时多个强符号同名就会触发链接器的「multiple definitions」错误——这是符合新C标准的行为,并非特性变更,而是默认编译标准的切换。
如何恢复CSAPP中的行为?
如果需要让链接器回到合并common symbol的旧行为,可以使用GCC的-fcommon编译选项:
gcc -fcommon b1.c b2.c
这样两个文件中的int x;会被当作common symbol处理,链接时自动合并为一个变量,不会报错。
其他合规的解决方式
- 显式声明extern:在其中一个文件中将变量改为引用而非定义,比如修改b2.c:
// b2.c extern int x; // 仅引用b1.c中定义的x,不创建新符号 - 使用弱符号:如果确实需要利用弱符号特性,显式声明其中一个变量为弱符号:
// b2.c int __attribute__((weak)) x; // 弱符号,链接时优先使用b1.c中的强符号x
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

