强符号和弱符号
如果多个目标文件包含同名的全局符号定义,那么如果这些目标文件链接时,就会出现符号重定义错误。
这类符号成为强符号(Strong Symbol)。有些符号可以被定义为弱符号(Weak Symbol)。
对于C/C++来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。
对于gcc,可以通过__attribute__((weak))来定义弱符号。
__attribute__((weak)) int global = 12;
对于强弱符号,链接器会按如下规则处理和选择被多次定义的全局符号:
1. 不允许强符号被多次定义。如果有多个强符号,会报符号重定义错误
2. 如果有一个强符号,其他定义都是弱符号,则选择强符号.
3. 如果一个符号在所有文件中都是弱符号,则选择其中一个占用空间最大的。比如目标文件A中定义全局变量nGlobal为int型,占4字节;在B文件中同样定义nGlobal 为double型,占8字节;链接后nGlobal占8字节。
强引用和弱引用
对外部目标文件的符号引用在这个目标文件被链接成可执行文件时,要找到这些符号的定义,如果没有找到,链接器就会报符号位定义错误。这被称为强引用。
与之对应的是弱引用,如果没有找到符号定义,则链接器默认其值为0,或者是一个特殊的值,以便程序代码能后识别。
弱符号和弱引用对于库来说十分有用。用户可以定义强符号来覆盖库定义的弱符号,从而使程序可以使用自定义版本的库函数。
也可以将某些功能模块的引用定义为弱引用,当模块与程序正常链接时,该功能可以正常使用;如果去掉了这块功能,程序也可以正常链接,只是缺少了这部分功能。比如
__attribute__((weakref)) void foo(); //__attribute__((weakref))来声明一个引用是弱引用 int main() { if(foo) foo(); }
如上面的代码所示,如果foo在外部目标文件被定义了,那么main中可以正常使用foo();如果目标文件已经将foo()部分删除,也不会影响main函数的正常运行。