neu*_*ont 8 c++ compiler-construction linker inline redefinition
我花了几天时间处理一个奇怪的问题,最后发现项目中有两个inline相同签名的功能,导致了问题.为了简化这种情况,这里有一个例子:两个cpp文件:
a.cpp
#include <iostream>
void b();
inline void echo()
{
std::cout << 0 << std::endl;
}
int main()
{
echo();
b();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
和b.cpp
#include <iostream>
inline void echo()
{
std::cout << 1 << std::endl;
}
void b()
{
echo();
}
Run Code Online (Sandbox Code Playgroud)
请注意,inline功能echo具有相同的签名但不同的工具.编译并运行
g++ a.cpp b.cpp -o a.out && ./a.out
Run Code Online (Sandbox Code Playgroud)
或者像这样
g++ a.cpp -c
g++ b.cpp -c
g++ a.o b.o -o a.out
./a.out
Run Code Online (Sandbox Code Playgroud)
它打印0 0.(我正在使用g ++ 4.6.1,我用clang ++ 2.9测试,结果相同)
如果启用优化,就不会发生这种情况
g++ -O3 a.cpp b.cpp -o a.out && ./a.out
Run Code Online (Sandbox Code Playgroud)
现在是0 1这个时候.
我的问题是,无论结果如何或编译如何执行,都没有错误甚至警告我多次定义inline函数.在这种情况下,编译器和链接器究竟发生了什么?
编辑:
看一下目标文件中的符号
nm a.o b.o | c++filt
Run Code Online (Sandbox Code Playgroud)
两个文件都有记录echo().所以我认为问题发生在链接时.可以说连接器随机选择一个实现并丢弃所有其他实现吗?
编译器不需要诊断此ODR违规,这并非易事.该inline关键字是指不同的翻译单位可能具有相同的符号,因此它被标记由编译器弱.基本用例是在标题中内联定义的函数:包含标题的所有翻译单元都将具有定义,并且完全没问题.编译器只需要丢弃除一个定义之外的所有定义,并在任何地方使用该定义.
检测不同的定义是否完全匹配是一个复杂的问题.链接器必须分析生成的二进制实现并确定两个二进制代码是否与相同的源代码相关.大多数编译器都没有支持来确定这一点.
至于您的特定问题,我不可能知道导致两个函数被标记为内联的基本原理,但常见的错误是使用inline关键字来表示优化而不是在链接时不抱怨重复.该inline关键字是有道理的头,但在cpp文件没有这么多.在cpp文件中,如果要将某段代码分解为辅助函数,则应该static在未命名的命名空间中标记或定义该函数.如果该函数是static编译器知道该函数的所有用法都在你的翻译单元中,并且它有更多的知识来决定它是否想要内联函数调用(请注意即使你没有内联它也可以内联)告诉它,就像它决定不内联即使你告诉它一样.
| 归档时间: |
|
| 查看次数: |
1660 次 |
| 最近记录: |