【问题标题】:Inline function linkage内联函数联动
【发布时间】:2020-06-02 11:55:21
【问题描述】:

我无法理解以下行为:一个标头具有一些基本类型,而另一个标头中我在多个函数中使用了这些类型。之后,我开始根据我定义的类型和函数构建类。如果我留下以下签名,则在函数头中:

void whateverFunction(parameters)

链接器指出,whateverFunction 有多个定义。现在如果将其更改为:

inline void whateverFunction(parameters)

链接问题消失了,所有编译和链接都很好。我所知道的关于 inline 的是,它用它的代码替换了每个函数调用,而不是它非常黑暗,所以我的问题是:

链接器如何处理 C++ 中的内联函数?

【问题讨论】:

标签: c++ function inline


【解决方案1】:

当标头中的函数不是内联函数时,该函数的多个定义(例如在多个翻译单元中)是违反 ODR 规则的。

默认情况下内联函数具有外部链接。因此,由于 ODR 规则(如下所示),这样的多重定义(例如在多个翻译单元中)是可以的:

$3.2/5-“可能不止一个 类类型的定义(第 9 条), 枚举类型(7.2),内联 与外部链接功能 (7.1.2),类模板(第 14 条), 非静态函数模板(14.5.6), 类模板的静态数据成员 (14.5.1.3),类的成员函数 模板 (14.5.1.1) 或模板 一些模板的专业化 未指定参数(14.7, 14.5.5) 在程序中,前提是每个定义以不同的形式出现 翻译单位,并提供 定义满足以下 要求。给定这样一个实体 命名为 D 定义在多个 翻译单元,然后

——D 的每个定义应包括 相同的令牌序列;和 [...]

链接器如何处理内联函数几乎是实现级别的细节。只要知道实现在 ODR 规则的限制范围内接受这样的多重定义就足够了

请注意,如果标题中的函数声明更改为“静态内联...”,则内联函数显式具有内部链接,并且每个翻译单元都有自己的静态内联函数副本。

【讨论】:

  • 默认情况下内联函数具有外部链接。:我发现这种说法具有误导性。内联代码根本没有链接,至少不在函数名下。见Marcelo's answer
  • 在现代编译器上,可以将inline 视为允许多重定义而不是优化提示的关键字。编译器可以决定不内联内联函数,链接器可以跨编译单元选择任何一个。程序员应确保跨编译单元的内联函数是相同的。否则会出现未定义的行为。
【解决方案2】:

链接器可能根本看不到内联函数。它们通常直接编译到调用它们的代码中(即,代码用于代替函数调用)。

如果编译器选择不内联函数(因为它只是一个提示),我不确定,但我认为编译器将它作为普通的非内联函数发出并以某种方式对其进行注释,因此链接器只是选择它看到的第一个副本并忽略其他副本。

【讨论】:

    【解决方案3】:

    内联只是掩盖了问题。有多个定义指出了某个地方的问题。

    请谨慎使用标题。不要忘记: - #ifndef HEADER_NAME / #define HEADER_NAME / #endif >> 避免多重包含。 - 不要使用间接包含:如果您在文件中使用类型,请添加相应的头,即使同一文件中的另一个头包含它。

    【讨论】:

    • 您可以包含来自两个不同翻译单元的相同标题,而守卫对您没有帮助。
    猜你喜欢
    • 2011-12-30
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多