不同库和链接顺序中的相同符号

时间:2015-03-16 14:46:57

标签: c++ c static-linking dynamic-linking multiple-definition-error

我有2个图书馆:test.1test.2。这两个库都包含一个全局 extern“C” void f();函数,具有不同的实现(测试只需cout)。

我做了以下测试:

测试1 动态链接:
如果我在可执行文件的makefile中添加libtest.1.so然后libtest.2.so,然后在f();中调用main,则会调用libtest.1.so->f()
如果我更改了makefile中的顺序,则调用libtest.2.so->f()

测试2 静态链接:
静态库

完全相同

测试3 动态加载
手动加载库时,一切都按预期工作。


我预计多个定义会出现错误,这显然不会发生。

此外,由于情况不同,这并没有打破单一定义规则。

它也不是一个依赖地狱(不是它与此有关),也不是任何链接惨败..

那么,这是什么?未定义的行为?未指明的行为?或者它确实取决于链接顺序?

有没有办法轻松检测到这种情况?


相关问题:
dlopen vs linking overhead
What is the difference between dynamic linking and dynamic loading
Is there a downside to using -Bsymbolic-functions?
Why does the order in which libraries are linked sometimes cause errors in GCC?
linking two shared libraries with some of the same symbols


编辑我再做了两次测试,证实了这个UB:

我在void g()中添加了第二个函数test.1,而不是test.2

使用动态链接和.so库,同样的情况发生 - f以相同的方式调用,g也是可执行的(如预期的那样)。

但是现在使用静态链接更改了一些内容:如果test.1test.2之前是,则没有错误,来自test.1的两个函数都会被调用。<登记/> 但是当订单改变时,会出现“多个定义”错误。

很明显,“不需要诊断”(参见@MarkB的答案),但有时发生错误是“奇怪的”,有时候 - 它没有。

无论如何,答案非常明确并解释了上述所有内容 - UB。

2 个答案:

答案 0 :(得分:8)

库是对象文件的集合。链接器根据需要从库中提取对象以满足未解析的符号。重要的是,链接器按照它们在命令行中出现的顺序检查库,只查看每个库一次(除非命令行多次提到库),并且只接受满足某些引用的对象。

在第一组测试中,一切都很清楚:链接器满足第一个可用库中对f()的引用,而且几乎就是它。

现在进行第二组测试。在成功案例test.1满足fg引用时,test.2无关紧要。在失败的情况下,test.2满足f引用,但g仍未定义。为了满足g,链接器必须从test.1中提取一些对象,这也恰好提供f。显然它是多重定义。

请注意,为了发生错误,您必须在同一对象中包含fg。如果test.1由2个对象组成(一个定义f,另一个定义g),则错误消失。

答案 1 :(得分:1)

这绝对违反了案例1和案例2中的一个定义规则。在案例3中,由于您明确指定要执行的函数版本,可能会也可能不会。违反ODR是未定义的行为,无需诊断。

3.2 / 3:

  

每个程序都应包含每个非内联的一个定义   在该程序中使用的函数或变量;没有诊断   必需的。