【问题标题】:Defined multiple times for the inline function, how possible?为内联函数定义了多次,怎么可能?
【发布时间】:2018-11-29 16:27:57
【问题描述】:

c++入门书的以下引用让我很困惑

与其他函数不同,可以定义 inline 和 constexpr 函数 在节目中多次。毕竟编译器需要 定义,而不仅仅是声明,以便扩展代码。 但是,给定 inline 或 constexpr 的所有定义都必须 完全匹配。结果, inline 和 constexpr 正常运行 在标题中定义。 -- C++ 入门第 5 版,240 页

“可能在程序中定义多次” 这句话让我很困惑。据我了解,可以多次声明,但只需要定义一次。

谁能给我一个例子,为什么会有多重定义。

【问题讨论】:

标签: c++ compiler-errors linker inline


【解决方案1】:

在一个头文件中(我们称之为foo.h)你可以拥有

inline int foo() { /* do stuff */ }

现在,如果您在几个 cpp 文件中包含 foo.h,那么将在每个文件中定义 foo,这将是一个多重定义错误。由于foo 被标记为inline,所以没关系,因为所有定义都相同。

据我了解,声明可以多次,但定义只需要一次

编译器在翻译单元(基本上是一个 cpp 文件)上工作,它可以在其中进行各种优化,但函数内联和constexpr 要求编译器知道函数的定义。这意味着每个翻译单元都需要在其中定义函数。我们使用 inline 来解决这个问题,否则会出现多重定义错误。

【讨论】:

    【解决方案2】:

    举个例子。此版本无效。

    // main.cpp
    inline int square(int num) {
        return num * num;
    }
    
    inline int square(int num) {
        return num * num;
    }
    
    int main()
    {
        return square(2);
    }
    

    https://godbolt.org/z/nlSbxg

    但是当您在多个 .cpp 文件(又名翻译单元)中拥有它时,它是可以的,因为它现在是链接器的工作来做正确的事情。

    // b.cpp
    inline int square(int num) {
        return num * num;
    }
    
    // main.cpp
    inline int square(int num) {
        return num * num;
    }
    
    int main()
    {
        return square(2);
    }
    

    构建:gcc main.cpp b.cpp #include 的工作方式相同,它会将代码放在那些 .cpp 文件中。

    当然,如果函数体是内联,那么没有什么可以链接的,所以没问题:)

    如果编译器决定执行一个外联版本,您最终会得到多个目标文件 (.o) 具有相同“内联”函数的定义。这样的定义将被标记。

    多亏了那个标记链接器不会产生它找到了多个定义,而只会选择它找到的第一个。

    因此,如果所有定义都真正相同,那很好!如果我们有不同的这种功能体,我们就会遇到麻烦。文件b.cpp中的示例

    // b.cpp
    inline int square(int num) {
        return 1;
    }
    

    同一个内联函数有多个不同的定义是未定义的行为。它当然会编译,但我们得到了什么?这取决于链接器的选择:D

    【讨论】:

      【解决方案3】:

      我认为问题在于我们可以通过“定义”来表示多种含义。当您在头文件中编写内联函数时,它只被“定义”一次,因为在您的源代码中只有一个具有该名称的函数。

      但这不是编译器和链接器看待世界的方式。如果您在从a.cppb.cpp 调用的头文件中有一个内联函数foo,那么该函数的完整编译版本将包含在a.objb.obj 中。链接器通过仅选择其中一个编译版本包含在最终二进制文件中来解决问题。

      请注意,我在这里掩盖了重要的细节,但这是一般的想法(我认为你的教科书没有做到这一点)。

      【讨论】:

        猜你喜欢
        • 2011-05-09
        • 2011-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-20
        • 2020-07-23
        • 1970-01-01
        相关资源
        最近更新 更多