18

在 C++ 中,关键字“inline”有两个用途。首先,它允许定义出现在多个翻译单元中。其次,它是对编译器的一个提示,一个函数应该内联在编译后的代码中。

我的问题:在 GCC 和 Clang/LLVM 生成的代码中,关键字“inline”是否对函数是否内联有任何影响?如果是,在什么情况下?还是完全忽略了提示?请注意,这不是语言问题,而是特定于编译器的问题。

4

4 回答 4

10

[警告:不是 C++/GCC 大师] 你需要在这里阅读 inline

此外,这适用于 GCC/C99。

通过使用内联函数说明符提出的建议的有效程度(C99 6.7.4)。

  • 如果使用了 -fno-inline 选项或使用了 -O0,GCC 将不会内联任何函数。否则,GCC 可能仍然无法内联函数,原因有很多;-Winline 选项可用于确定函数是否未内联以及为什么不内联。

因此,除非使用您的编译器设置(如-fno-inlineor -O0),否则编译器似乎会提示。我无法评论 Clang/LLVM(或真正的 GCC)。

-Winline如果这不是代码高尔夫问题并且您需要知道发生了什么,我建议使用。

于 2011-03-07T18:56:19.403 回答
7

gcc的一个有趣的解释:内联函数与宏一样快

一些调用由于各种原因不能被集成(特别是函数定义之前的调用不能被集成,定义中的递归调用也不能被集成)。如果有一个非集成调用,那么该函数像往常一样被编译为汇编代码。如果程序引用它的地址,该函数也必须像往常一样编译,因为它不能被内联。

请注意,函数定义中的某些用法可能使其不适合内联替换。这些用法包​​括:可变参数的使用、alloca 的使用、可变大小数据类型的使用(请参阅可变长度)、计算 goto 的使用(请参阅作为值的标签)、非本地 goto 的使用和嵌套函数(请参阅嵌套函数)。使用 -Winline 将在标记为 inline 的函数无法替换时发出警告,并给出失败的原因。

根据 ISO C++ 的要求,GCC 认为在类的主体中定义的成员函数被标记为内联,即使它们没有使用 inline 关键字显式声明。您可以使用 -fno-default-inline 覆盖它;请参阅控制 C++ 方言的选项。

GCC 在不优化时不会内联任何函数,除非您为函数指定 `always_inline' 属性,如下所示:

 /* Prototype.  */
 inline void foo (const char) __attribute__((always_inline)); The remainder of this section is specific

到 GNU C90 内联。

当内联函数不是静态的时,编译器必须假设可能有来自其他源文件的调用;由于一个全局符号在任何程序中只能定义一次,因此不能在其他源文件中定义该函数,因此不能集成其中的调用。因此,非静态内联函数总是以通常的方式自行编译。

如果在函数定义中同时指定 inline 和 extern,则该定义仅用于内联。在任何情况下,该函数都不会自行编译,即使您明确引用其地址也是如此。这样的地址变成了外部引用,就好像您只声明了函数,而没有定义它。

这种 inline 和 extern 的组合几乎具有宏的效果。使用它的方法是将函数定义放在带有这些关键字的头文件中,并将定义的另一个副本(缺少内联和外部)放在库文件中。头文件中的定义将导致对函数的大多数调用被内联。如果该函数的任何用途仍然存在,它们将引用库中的单个副本。

于 2011-03-07T19:30:48.817 回答
5

通过阅读 GCC 和 LLVM 项目的代码,可以收集到很多信息。这是通过直接阅读代码收集的一些信息。(注意:这不一定是完全全面的,也没有列出inline影响每个细节中内联的每一种方式,只是对其中的大部分进行概述)

该信息是从 GCC 和截至 2021 年 11 月 13 日的 LLVM 当前开发 HEAD 收集的,因此将来可能不是最新的。

在 GCC 方面:

在 LLVM 方面:

换句话说,在 GCC 和 Clang 上,这似乎是一个非常强烈的提示。

于 2021-11-13T17:23:35.553 回答
4

提示的强度完全取决于您使用的编译选项。大多数编译器可以选择不进行内联,只内联标记为“内联”的那些,或者使用其最佳判断并忽略提示。

最后一个可能效果最好。:-)

于 2011-03-07T19:05:13.727 回答