c++中符号重定义问题
在开发比较大的项目时,有时候会出现多动态库之间定义了重复名字的情况,或者动态库和主程序之间定义了重复名字的情况。
在gcc上验证
编译器版本是gcc4.8,在linux下进行了测试,动态库都是.so文件
动态加载
如果.so文件是动态加载到主程序中的,即使双方有同名的全局变量,也互相不影响,各自用它们自己的全局变量。(前提是.so文件事先没有被链接到主程序)
动态链接
.so文件在编译后被立即链接到主程序,程序启动后.so文件不会重新初始化这个变量,而是使用主程序的全局变量的值。如果.so文件后续使用了这个变量,则程序的行为可能不符合.so文件编写者的预期,因为.so文件的编写者还以为他使用的是.so文件自己定义的全局变量
主程序和.so文件事先进行了链接,主程序又动态加载了.so文件
这时,由于主程序和so事先进行了链接,因此so会使用主程序中定义的全局变量,但是由于so是后来动态加载进来的,所以当so被关闭时,so要去析构这个变量,这就会导致主程序里的全局变量受到影响。
建议
不是很清楚这种符号重定义是不是未定义行为,但是毫无疑问会出现不符合用户预期的结果,解决办法:
- 编译.so文件时加上链接参数
-Wl,-Bsymbolic,强制要求.so文件使用他自己的符号。 - 使用编译选项
-fvisibility=hidden和-fvisibility-inlines-hidden隐藏库内部的所有符号,并配合__attribute__((visibility("default"/"hidden")))手动控制名字是否导出。 - 使用命名空间控制名字的可见性。