兼容 c++11 的编译器是不是总是忽略内联提示?
Posted
技术标签:
【中文标题】兼容 c++11 的编译器是不是总是忽略内联提示?【英文标题】:Do c++11-compatible compilers always ignore inline hints?兼容 c++11 的编译器是否总是忽略内联提示? 【发布时间】:2015-11-09 22:01:24 【问题描述】:在When should I write the keyword 'inline' for a function/method? 上阅读old answer,上面写着:
据说内联提示编译器你认为函数应该被内联。这在 1998 年可能是正确的,但十年后编译器不需要这样的提示。更不用说在优化代码时人类通常是错误的,所以大多数编译器完全忽略了“提示”。
这个答案是在 2009 年发布的,所以我想最终弄清楚:
-
现代 c++11 兼容编译器是否总是忽略用户指定的
inline
提示并且仅自动执行此操作?
inline
提示是否只保留以提供向后兼容性?
如果不是1.
那么这个答案不正确?
【问题讨论】:
@iammilind 所以,回答你的问题表明clang
不要忽略使current answer 错误的提示,因为现在至少clang
仍在搜索inline
关键字并做出一些决定。
是的。具有讽刺意味的是,与 2014 年 11 月给出的答案相比,2009 年 11 月给出的答案更现代。我希望前者是真的,这是我问这个问题时的确切假设。很有可能,2014 年 11 月给出的答案可能是 Clang 限制的一个孤立场景。无论如何,我将通过列出possible duplicate 来标记重新打开这个问题。
一些编译器让你选择。例如,MSVC 有以下选项:根本不内联任何东西,内联只是标记为 inline
的函数,或内联显然应该是的任何东西(无论它是否标记为 inline
)。
您误解了您链接到的答案,或者没有完全阅读。答案并没有说inline
只是一个被忽略的提示,它说inline
改变了语言语义,以便可以在多个翻译单元中定义一个函数。这不仅是为了向后兼容而保留的,它还是 C++ 语言和链接模型的一个重要属性。所以你的整个问题似乎是基于一个有缺陷的前提。 inline
不仅仅是“提示”,它改变了代码的编译+链接方式,使得编译器可以进行内联(没有 LTO)。
@jonathan namespace
也允许这种情况在没有 LTO 的情况下发生,并且不太可能导致 ODR 违规。 (现在,static
locals 在您想要内联的非 LTO 函数中,那么您仍然需要它!)
【参考方案1】:
-
不,他们只是按照标准的要求解释它,但一些编译器可能只做这些(根据文档 MSVC 选择基于
inline
关键字的存在,但 GCC 5.1.0 也采用 @987654322 @关键字在决定时考虑)。
不,链接时也需要内联以避免重复符号。
inline
关键字确实有意义,但不是您可能期望的含义。这并不意味着编译器必须/应该/可能内联扩展函数,无论您是否使用inline
,编译器都可以决定按照它认为合适的方式进行操作。
这意味着您应该并且可以在每个使用它的编译单元中重复函数定义,而不会导致链接错误 - 非常类似于 static
关键字。
例如 GCC 4.7.2(它可能不是最先进的,但仍然是一个相当现代的编译器)似乎对 inline
的解释不超过标准的规定。如果禁用优化并且打开优化,它似乎不会内联该功能,无论如何它似乎都是内联的。唯一的区别是编译器在不同情况下如何处理“概述”函数,内联它只是将其丢弃或以避免链接时重复符号的方式处理它。
【讨论】:
我认为 Victor 明白inline
是一个提示,他在问现代编译器是否仍然将其作为提示,或者他们是否通常忽略它。
这已在问题发布的链接中的所选答案中进行了解释。
如果我今天正在编写一个编译器,我可能会使用 inline 关键字在性能大致相等的两个选项之间进行选择(内联与否),所以如果编译器无法生成坚定决定走哪条路,跟着提示走!但这只是我。
@VictorPolevoy 我看不出你想要什么样的答案。一些编译器不会根据 inline
关键字选择内联,而一些编译器可能会基于此进行选择。
@Yakk 是的,这很讨厌,但我目前不知道在答案中应该如何提及。【参考方案2】:
现代的 c++11 兼容编译器是否总是忽略用户指定的内联提示,并且仅自动执行此操作?
C++11 在这里无关紧要,C++11 标准没有改变 inline
的语义,编译器优化很大程度上独立于正在编译的语言版本。
是否只保留内联提示以提供向后兼容性?
不,inline
不是提示,编译器不会“忽略”inline
,因为如果这样做,您会收到多个定义错误。编译器赋予inline
关键字的含义并不是您似乎理解的含义。这不是提示。
如果编译器看不到函数定义,它就不能内联它(链接时间优化改变了这一点,但 LTO 的使用还不是很普遍,而且大多数库不附带允许 LTO 的二进制文件链接时内联)。
您应该将inline
理解为“此函数定义在此文件中内联显示”而不是“对该函数的调用应内联”。
所以inline
关键字对于允许编译器查看多个文件中的函数定义很有用,这意味着它可以可能通过内联调用来优化调用。这并不一定使它比在同一翻译单元中定义的任何其他函数更有可能被内联。
对于从多个翻译单元调用的函数,在标头中定义函数并使它们inline
是编译器内联它们的必要条件,但这还不够足够 strong>(因为编译器根据其他条件进行内联决策)。
这与向后兼容性无关,今天和 2009 年一样。
【讨论】:
内联缺少 ODR 危险。和 C++11 替代匿名命名空间。 @Yakk,为什么匿名命名空间是 C++11 的替代方案?它们也存在于 C++03 中。我没有提到使用它们或static
,因为它们是不同的解决方案,具有不同的结果,而不仅仅是使用inline
函数的替代品。它们解决了一个不同的问题(如果它们没有内联,由于链接器需要保留所有定义,可能会导致代码大小显着增加)。
@VictorPolevoy,答案不清楚吗?如果要在标题中定义函数而不会出现多个定义错误,则应使用 inline 关键字。这正是old answer 所说的。你不明白哪一部分?这显然不是没用,因为如果你从头文件中定义的函数中删除inline
,代码将不会链接。
认真的吗?在标题中定义一个函数,不带inline
。将标题包含在两个不同的文件中。将文件链接在一起。
广泛使用的是什么?头文件?职能?是的。【参考方案3】:
C++11 编译器遵循与 C++03 或任何版本的语言相同的内联提示。
但是,请注意inline
关键字不是内联提示。提示看起来更像__attribute__((always_inline))
。
inline
关键字(或隐式内联状态,应用于模板等)表示函数定义在头文件中,因此链接器在组合翻译单元时应该看到它的多个副本(@987654324 @ 文件)。之所以如此命名,是因为定义必须可用才能内联函数,这意味着库中的函数实际上需要 inline
才能内联。
【讨论】:
以上是关于兼容 c++11 的编译器是不是总是忽略内联提示?的主要内容,如果未能解决你的问题,请参考以下文章