【问题标题】:What if redefine an inline function?如果重新定义内联函数怎么办?
【发布时间】:2011-10-14 03:58:58
【问题描述】:

我在一个奇怪的问题上花了几天时间,终于发现项目中有两个相同签名的inline函数,它们导致了这个问题。为了简化情况,这里举个例子:两个cpp文件:

a.cpp

#include <iostream>

void b();

inline void echo()
{
    std::cout << 0 << std::endl;
}

int main()
{
    echo();
    b();
    return 0;
}

和 b.cpp

#include <iostream>

inline void echo()
{
    std::cout << 1 << std::endl;
}

void b()
{
    echo();
}

请注意inline 函数echo 具有相同的签名但不同的实现。编译运行

g++ a.cpp b.cpp -o a.out && ./a.out

或者像这样

g++ a.cpp -c
g++ b.cpp -c
g++ a.o b.o -o a.out
./a.out

它打印0 0。 (我为此使用了 g++ 4.6.1,并使用 clang++ 2.9 进行了测试,结果相同)

如果开启优化就不会发生这种情况,比如

g++ -O3 a.cpp b.cpp -o a.out && ./a.out

这次是0 1

我的问题是,无论结果或编译如何执行,都没有错误甚至警告我多次定义了inline 函数。在这种情况下,编译器和链接器到底会发生什么?

编辑:

看看目标文件中的符号

nm a.o b.o | c++filt

两个文件都有记录echo()。所以我认为问题发生在链接时。是否可以说链接器随机选择一种实现并丢弃所有其他实现?

【问题讨论】:

  • 您是否尝试过更高的警告详细程度(-Wall 等)?
  • 我刚刚试过-Wall -Wextra,还是没有警告。

标签: c++ compiler-construction linker inline redefinition


【解决方案1】:

在 C++ 标准中规定,内联函数的所有定义都应相同,但不需要诊断。也就是说,您的程序不是有效的 C++ 程序,但实现有权不检测该错误。

参见第 3.2.5 条。在这里发帖太长了。

【讨论】:

    【解决方案2】:

    这种情况(两个具有相同名称和相同签名的内联函数具有不同的实现)leads to undefined behavior。编译器不需要对其进行诊断,尽管它可以尝试。

    【讨论】:

      【解决方案3】:

      编译器不需要诊断此 ODR 违规,而且这不是微不足道的。 inline 关键字意味着不同的翻译单元可能具有相同的符号,因此编译器将其标记为弱。基本用例是在标题中内联定义的函数:包含标题的所有翻译单元都将具有定义,这非常好。编译器只需要丢弃除一个定义之外的所有定义并在任何地方使用该定义。

      检测不同的定义是否完全匹配是一个复杂的问题。链接器必须分析生成的二进制实现并确定两个二进制代码是否与相同的源代码相关。大多数编译器不支持确定这一点。

      对于您的特定问题,我不可能知道导致两个函数被标记为内联的原因,但一个常见错误是使用 inline 关键字来表示 optimize 而不是 不要在链接时抱怨重复inline 关键字在标头中有意义,但在 cpp 文件中意义不大。在 cpp 文件中,如果您想将某些代码分解为辅助函数,则该函数应标记为 static 或在 unnamed 命名空间中定义。如果函数是static,那么编译器知道该函数的所有用法都在您的翻译单元内,并且它有更多的知识来决定是否要内联函数调用(注意它可以内联,即使你不告诉它,就像即使你告诉它它也可以决定不内联一样)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 2022-10-07
        • 2011-03-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多