如何使 ld 将 Multiply 定义的结构/类视为错误?

Posted

技术标签:

【中文标题】如何使 ld 将 Multiply 定义的结构/类视为错误?【英文标题】:how to make ld treat Multiply defined structs/classes as an error? 【发布时间】:2012-05-11 11:04:42 【问题描述】:

编辑——澄清我的问题的目标: 我浪费了很多时间来诊断我希望链接器报告的问题,这是由公认的糟糕的编程风格引起的,例如将一段代码从一个编译单元复制粘贴到另一个编译单元,然后对其进行修改。

我正在寻找一种在编译/链接时检测此问题的方法。

在此设置中:

啊.h

void foo();

A.cpp

struct A  
  int values[100];
  A() 
    std::cout << __FILE__ << ": A::A()\n";
;
void foo() 
   A a;

ma​​in.cpp

#include "A.h"
struct A  
  double values[100];
  A() 
  std::cout << __FILE__ << ": A::A()\n";
;
int main() foo(); 
// void foo() ===> this would cause a linker error

我希望链接器报告结构 A,或至少构造函数 A::A(),被定义了两次。

但是,g++ 4.4 链接就好了。运行代码显示,在这种情况下,链接器选择使用来自 A.cpp 的A

$ g++ -Wall A.cpp main.cpp && ./a.out
A.cpp:3
A.cpp:7
A.cpp:3

函数 foo() 出现在两个目标文件中时,链接器会报告多重定义,但对于结构,它不会。

编辑:刚刚通过使用 nm -C *.o 发现 A.o 和 main.o 都将 A::A() 定义为 弱符号。这使得它可以从具有相同名称的符号池中“选择”。也许问题可以改写为“我怎样才能使编译器生成 strong 符号?”...

00000000 W A::A()

我怎样才能发现这个问题?

【问题讨论】:

像你刚才所做的那样在类中定义一个成员会隐式声明该成员为inline,这样实现将允许你在整个程序中提供多个该成员的定义。仍然要求所有这些定义彼此足够相似(我认为由于使用了__FILE__ 而不是这种情况),但这更难诊断(并且不是必需的)。 @LucDanton: 足够相似完全一样,否则你就违反了ODR。 @LucDanton:我明白你的意思,但在这种情况下,nm 输出清楚地表明所述函数没有被内联,不是吗? @xtofl 不要错误地认为inline 关键字与内联有任何关系(不应该责怪任何人)。它与 ODR 相关——在这里,通过使用 inline(虽然是隐含的),您要求的是 ODR 的特殊版本,这使得诊断更加困难。由于您想要更多诊断,请删除inline——加上将定义与声明分开通常也是更好的风格。 @LucDanton:不要让标准混淆你,没有比标准提供的更严格的完全相同定义:代码必须是同样,代码引用的对象必须是完全相同的对象,除非不可能,在这种情况下不能使用对象的标识,只能使用值,并且值必须完全相同。如果没有这个例外,这将违反 ODR:const int k = 10; inline int f() return k; ,因为常量具有内部链接,因此包含它的每个 TU 都有不同的k 【参考方案1】:

也许问题可以改写为“我怎样才能使编译器生成强符号?”...

尽量限制inline函数的使用:

struct A 
    A();
;

// Inside A.cpp
A::A()  
    std::cout << __FILE__ << ": A::A()\n";

实现更有可能报告未声明 inline 的函数的 ODR 违规(包括隐式声明 inline 的函数,例如在类定义中定义的成员) ,尽管严格来说从来不需要这样的诊断。

【讨论】:

【参考方案2】:

这不是问题,也不是重新定义。这就是 C++ 的工作原理。想想看——你把类 definitions 放在头文件中(只暴露声明远不常见)。标题几乎被复制粘贴到每个使用它们的翻译单元中。 不能在多个 TU 中拥有同一类的多个定义是错误的。所以,这不是要解决的问题。

但是,如果在同一个名称下定义了不同的类,编译器/链接器应该会报错。

【讨论】:

...当然,后者是问题真正造成伤害的时候。在过去的十年中,我已经花费了几个小时,遇到了分段错误(最佳情况)和由该问题引起的内存损坏。因此提出了这个问题。

以上是关于如何使 ld 将 Multiply 定义的结构/类视为错误?的主要内容,如果未能解决你的问题,请参考以下文章

使 /etc/ld.so.conf 中的 ld 忽略目录

text JSON-LD中的Schema.org类层次结构

如何在需要等待内容加载的动态页面上使用 JSON-LD 添加结构化数据?

C++ Multiply Defined constructor 错误消息似乎是错误的

PyQt4 - 自定义小部件类结构?

群体遗传分析方法:LD,FST,eQTL