Skip to content

c++中符号重定义问题

在开发比较大的项目时,有时候会出现多动态库之间定义了重复名字的情况,或者动态库和主程序之间定义了重复名字的情况。

在gcc上验证

编译器版本是gcc4.8,在linux下进行了测试,动态库都是.so文件

动态加载

如果.so文件是动态加载到主程序中的,即使双方有同名的全局变量,也互相不影响,各自用它们自己的全局变量。(前提是.so文件事先没有被链接到主程序)

动态链接

.so文件在编译后被立即链接到主程序,程序启动后.so文件不会重新初始化这个变量,而是使用主程序的全局变量的值。如果.so文件后续使用了这个变量,则程序的行为可能不符合.so文件编写者的预期,因为.so文件的编写者还以为他使用的是.so文件自己定义的全局变量

主程序和.so文件事先进行了链接,主程序又动态加载了.so文件

这时,由于主程序和so事先进行了链接,因此so会使用主程序中定义的全局变量,但是由于so是后来动态加载进来的,所以当so被关闭时,so要去析构这个变量,这就会导致主程序里的全局变量受到影响。

建议

不是很清楚这种符号重定义是不是未定义行为,但是毫无疑问会出现不符合用户预期的结果,解决办法:

  1. 编译.so文件时加上链接参数-Wl,-Bsymbolic,强制要求.so文件使用他自己的符号。
  2. 使用编译选项-fvisibility=hidden-fvisibility-inlines-hidden隐藏库内部的所有符号,并配合__attribute__((visibility("default"/"hidden")))手动控制名字是否导出。
  3. 使用命名空间控制名字的可见性。