【发布时间】:2015-10-21 17:37:00
【问题描述】:
所以我在 2 个独立的翻译单元中有这段代码:
// a.cpp
#include <stdio.h>
inline int func() { return 5; }
int proxy();
int main() { printf("%d", func() + proxy()); }
// b.cpp
inline int func() { return 6; }
int proxy() { return func(); }
正常编译时,结果为10。当使用 -O3(内联)编译时,我得到 11。
我明显违反了func() 的 ODR。
当我开始将不同 dll 的源合并为更少的 dll 时,它就出现了。
我试过了:
- GCC 5.1
-Wodr(需要-flto) - 带有
-detect-odr-violations的黄金链接器 - 在使用地址清理程序运行检测二进制文件之前设置
ASAN_OPTIONS=detect_odr_violation=1。
据称,Asan 可以捕获其他 ODR 违规行为(具有不同类型的全局变量或类似的东西......)
这是一个非常讨厌的 C++ 问题,我惊讶没有可靠的工具来检测它。
也许我误用了我尝试过的工具之一?或者有什么不同的工具可以做到这一点?
编辑:
即使我使func() 的两个实现完全不同,因此问题仍然没有被注意到,因此它们不会被编译成相同数量的指令。
这也会影响类体内定义的类方法 - 它们是隐式内联的。
// a.cpp
struct A { int data; A() : data(5){} };
// b.cpp
struct A { int data; A() : data(6){} };
带有大量复制/粘贴 + 小修改的遗留代码是一种乐趣。
【问题讨论】:
-
我想知道在 .cpp 文件中包含
inline函数的用例是什么。我想不出任何可能的优势。 -
@sjdowling 为什么是 inline 关键字?遗留代码。还要考虑这个:
struct A { A(){} };- 这里的构造函数是在结构定义内定义的,并且是隐式内联的。 2 个这样的结构可能具有相同的布局但不同的内联方法... -
在此遗留代码中查找这些 ODR 违规的最简单方法可能是从 .cpp 文件中定义的函数中删除所有
inline说明符并检查任何导致的链接错误。 -
我喜欢你如何使用“遗留”来表示“破碎”。这段代码从来没有是个好主意。
标签: c++ linker g++ linker-errors one-definition-rule