标题中定义的函数是否保证内联?

时间:2010-03-06 03:56:26

标签: c++ inlining

如果我在标题中定义非成员函数,它是否总是由编译器内联,或者编译器是否根据其启发式选择?我知道__inline只是一个提示,是否与标题中的函数相同?

5 个答案:

答案 0 :(得分:11)

请记住,在标题中包含某些内容与直接在源文件中输入内容没有什么不同。因此,就编译器而言,在头文件中没有任何区别;它从来不知道它在那里。

因此,当您在头文件中定义一个函数,并将该头文件包含在文件中时,就像您只是直接在文件中键入该函数一样。所以现在的问题是,“编译器是否选择基于启发式内联事物?”

答案是“这取决于编译器”。该标准不保证内联或不内联。也就是说,任何现代编译器都会对其内联的内容非常聪明,可能具有启发式。

但是,我们谈到了一个有趣的观点。想象一下,您在标题中有一个函数,并在多个源文件中包含该标题。然后,您将跨翻译单元对函数进行多个定义,这违反了单定义规则。因此,您将收到编译错误。 (链接器错误通常类似于:“错误,函数x已在y中定义”)您可以使用inline关键字,而不再违反ODR。

顺便说一下,__inline是非标准的。与您的帖子相反,它通常是强制内联的编译器扩展,而不是暗示它。 inline是标准关键字,最初旨在暗示内联。就像你说的那样,大多数现代编译器在这方面都完全忽略了它,现在唯一的目的就是给内部联系。

答案 1 :(得分:4)

来自C++ FAQ Lite

  

无论你如何指定一个功能   作为内联,它是一个请求   允许编译器忽略:它   可能内联扩展一些,全部或全部   对内联函数的调用。

答案 2 :(得分:2)

它将根据启发式选择。请确保将其明确声明为内联,否则如果在多个编译单元中包含标题,则可能会出现重复的符号链接错误。

答案 3 :(得分:2)

如果在头文件中定义具有外部链接的函数并将其包含在多个转换单元中,则会因违反一个定义而出现编译错误(更准确地说:链接器erorr)规则(ODR)。所以答案是“不”:编译器不会在头文件中定义函数作为内联提示,也不会让您无法遵守ODR的要求。不仅保证这些函数不被内联,而且很可能你的程序甚至不会编译。

为了在头文件中定义一个函数并远离它,你必须给它内部链接(声明它static,并在每个翻译单元中以单独的函数结束),或者明确声明它inline

至于启发式...现代编译器通常会考虑几乎所有内联函数(通过应用启发式),无论它在何处定义以及是否明确声明inline

答案 4 :(得分:1)

标题中的函数没有神奇之处。编译器甚至不知道函数是否在头文件中定义。 (由于标题实际上只是复制/粘贴到源文件中,您可以在标题中定义它,但编译器只是将其视为翻译单元的一部分)

还有两种不同的“内联”含义:

一个函数可以是 inlined ,如C ++标准所定义的:这可以通过在函数前加上inline关键字,或者如果它是一个成员函数,通过定义它来完成在类定义中就地。

这样做的效果是

  • 通知链接器它可能在多个文件中遇到函数定义,它应该只是默默地将它们合并在一起而不是抛出错误
  • 使编译器更容易执行内联优化

另一方面,内联优化只是被调用函数体替换函数调用的行为,这意味着此优化实际上应用于调用站点,而不是函数。通常可以在某些地方调用函数,但在其他地方内联。当编译器感觉它时,内联函数调用,并且最好在概念上将其完全与“内联”的第一个含义分开。

编译器将在内部,时间和地点应用内联优化。它使用了大量的启发式方法。较小的函数更有可能被内联。如果确定特定呼叫站点将被足够频繁地执行,则更可能被内联。最终,它使用的启发式基于“它会改善还是降低性能”。它通常比人类更好地判断这一点,因此您不应该真正需要知道它使用的精确启发式方法。内联太多只会损害性能。

相关问题