代码之家  ›  专栏  ›  技术社区  ›  Steve

是否保证在头中定义的函数是内联的?

  •  6
  • Steve  · 技术社区  · 15 年前

    如果我在头文件中定义了一个非成员函数,它将始终由编译器内联,还是由编译器根据它的试探性选择?我知道uu inline只是一个提示,它和header中的函数一样吗?

    5 回复  |  直到 15 年前
        1
  •  11
  •   GManNickG    15 年前

    请记住,包含头中的内容与直接在源文件中键入它没有什么不同。所以对于编译器来说,在头中没有区别;它从来不知道它在那里。

    所以当你在头文件中定义一个函数,并且你在一个文件中包含了头文件,就好像你直接在文件中输入了函数一样。所以现在的问题是,“编译器是否选择基于启发式的内联操作?”

    答案是“这取决于编译器”。标准不保证什么是内联的。也就是说,任何一个现代编译器都会对其内联的内容非常聪明,很可能使用启发式。

    然而,我们有一个有趣的观点。假设在头中有一个函数,并且在多个源文件中包含该头。然后,将跨翻译单元对函数进行多个定义,这违反了一个定义规则。因此,您将得到编译错误。(链接器错误通常是这样写的:“error,function x already defined in y”)您可以使用 inline 关键字和你不再违反ODR。

    顺便说一句 __inline 是非标准的。与您的文章相反,它通常是一个编译器扩展 军队 内联,而不是暗示它。 内联的 是标准关键字,最初用于提示内联。正如你所说,大多数现代编译器在这方面完全忽略了它,现在唯一的目的就是给事物内部的联系。

        2
  •  4
  •   mwigdahl    15 年前

    C++ FAQ Lite :

    不管你如何指定一个函数 作为内联,它是一个请求 允许编译器忽略:它 可能内联展开some、all或none 对内联函数的调用。

        3
  •  2
  •   Laserallan    15 年前

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

        4
  •  2
  •   AnT stands with Russia    15 年前

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

    为了在头文件中定义函数并摆脱它,必须给它内部链接(声明它 static ,并最终在每个翻译单元中使用单独的函数),或显式声明它 inline .

    至于启发法…现代编译器通常会考虑几乎任何用于内联的函数(通过应用启发式),而不管它是在何处定义的,以及是否显式声明的。 内联的 或者没有。

        5
  •  1
  •   Stack Overflow is garbage    15 年前

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

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

    函数可以是 内联 正如C++标准所定义的:这是通过用函数预定义函数来完成的。 inline 关键字,或者如果它是成员函数,则在类定义中就地定义它。

    这样做的效果是

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

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

    编译器将应用内联优化,如果,什么时候,在什么地方。它使用了很多启发式方法。较小的函数更可能是内联的。如果它确定一个特定的调用站点将被足够频繁地执行,那么它更有可能是内联的。最终,它使用的启发式方法是基于“它是否会提高或降低性能”。它通常比人类更能判断这一点,所以你不必知道它使用了什么精确的启发式方法。内联太多只会损害性能。