C语言中,"inline"关键字什么时候有效?

8

标准并不保证inline函数被实际内联,必须使用宏才能得到100%的保证。编译器总是根据自己的规则决定哪些函数是否内联,而不考虑inline关键字。

那么,当使用现代编译器(如最近版本的GCC)时,inline关键字什么时候会对编译器产生实际效果呢?


6
宏并不能百分之百保证。编译器可以自由地将重复的代码(来自宏的多次扩展)提取出来,变成对同一份代码的多次调用(相当于函数调用)。 - R.. GitHub STOP HELPING ICE
1
@R..:宏始终由预处理器在使用位置进行替换。之后,它们将受到与直接放置在函数内部的任何其他代码相同的优化影响。 - Ben Voigt
2
你应该仔细阅读在C99中,inline没有staticextern有用吗?,并且你也可以查看extern inline。请注意,尽可能使非内联函数成为static是值得的;如果有意义,编译器可能会将它们优化为内联代码,但只有在它知道该函数不会从当前源文件外部调用时才能这样做,这意味着该函数必须是static - Jonathan Leffler
2
@JonathanLeffler 小小的细节:编译器确实会内联非static函数,只是必须为外部调用者保留一个副本(增加代码大小)。不知道这是否会影响内联启发式算法。然而,有其他很好的理由使助手函数成为static(减少全局命名空间的污染,从而能够使用更短、更好的名称)。 - user395760
@delnan:我没有看到编译器内联非静态函数,但这并不意味着它不能或不会发生。 我写了我所知道的。 我认为,按默认情况使所有内容静态化,只有在知道当前源文件外部需要使用它时才公开它,这是一个好的规范。 是的,更方便的名称也可能是一个优点,只要你遵循使用适当系统化(通常更长)名称的纪律,如果必须将函数暴露给其他代码(你不会那么不专业地暴露变量的可见性,对吧?)记得及时更新头文件。 - Jonathan Leffler
显示剩余2条评论
2个回答

4
它具有语义效果。简单来说,标记为inline的函数可以在一个程序中定义多次 - 尽管所有定义必须相互等效 - 因此,在将函数定义包含在头文件中时需要存在inline以确保正确性(这反过来使得定义可见,以便编译器可以在没有LTO的情况下将其内联)。
除此之外,对于内联优化,“从不”是完全安全的近似值。它可能会在某些编译器中产生一些影响,但没有实际的硬数据,根本不值得失眠。例如,在以下代码中,使用Clang 3.0或GCC 4.7,无论是否标记inlinemain都包含相同的代码。唯一的区别是work是否作为独立函数保留供其他翻译单元链接,或者被删除。
void work(double *a, double *b) {
  if (*b > *a) *a = *b;
}

void maxArray(double* x, double* y) {
    for (int i = 0; i < 65536; i++) {
        //if (y[i] > x[i]) x[i] = y[i];
        work(x+i, y+i);
    }
}

对于一个语义效果,十1是可以的,但你需要稍微详细解释一下。inline并不免除你遵守“一个定义规则”。仍然必须有一个外部定义,并且如果它与内联定义不匹配,则结果是未定义的。 - R.. GitHub STOP HELPING ICE
@R.. 是的,我忽略了许多细节,其中一些我可能甚至没有意识到。我会加入一些模棱两可的措辞。 - user395760
3
“一次定义规则”是C++的一个术语,而C++中inline的语义与C的不匹配。即使在每个翻译单元中都有内联定义,C仍然需要一个外部定义,并且允许具有不同主体的内联定义(并且未指明调用哪个)。 - user743382
1
@hvd: 我认为在C语言中,并不总是需要对内联函数进行外部定义。如果你使用一个头文件来定义函数为 static inline ...,只要这个头文件在函数被使用的地方都被引用,就不会产生任何链接错误。 - Jonathan Leffler
1
@JonathanLeffler: 有了staticinline在语义上就相当于没有作用,因此非静态情况才是有趣的。另一方面,我认为通常你需要static。外部inline的语义太混乱了,特别是在某些GCC配置文件中默认使用的不兼容GNU语义的情况下。:( - R.. GitHub STOP HELPING ICE
显示剩余2条评论

1
如果您想控制内联,请使用编译器提供的任何指示符或属性来控制该行为。例如,在GCC和类似的编译器上使用__attribute__((always_inline))。正如您所提到的,inline关键字通常会根据优化设置等被忽略。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接