什么时候应该将函数设为内联?

82
为什么我要做这样的事情呢?
inline double square (double x) { return x * x; }

替代

double square (double x) { return x * x; }

有什么区别吗?

1
可能是内联函数 vs 预处理器宏的重复问题。 - Steve Jessop
2
实际上有很多重复和相似的内容:http://stackoverflow.com/search?q=c%2B%2B+inline。其中一些答案比其他答案更好,有些错误地声明`inline`关键字会导致函数在所有调用站点内联,等等。那可能不是最接近的重复内容。 - Steve Jessop
1
同时参见 C++ FAQ 中的内联函数。该文对内联函数有很好的阐述。 - jww
6个回答

93

前者(使用inline)允许您将该函数放在头文件中,从而可以在多个源文件中包含它。使用inline使标识符处于文件范围内,就像声明为static一样。如果不使用inline,则链接器会出现多个符号定义错误。

当然,这是另外一种提示编译器将函数编译为内联,直接嵌入到其使用的位置中(避免了调用函数的开销)。编译器不需要根据inline提示执行操作。


2
我认为inline的目的是让编译器在调用函数时“展开”函数内容,这样就不会有vtable查找(或在CPU级别跳转到函数指令)。 - DJ.
你的第一个点是预期目的的一个[有用]副作用吗? - Ian Fleeton
13
@Greg:它并不像“static”一样运作。如果是这样的话,每个翻译单元将对其函数副本拥有自己的所有权,并且链接器将把它们全部视为不同的函数(它们恰好具有相同的名称)。相反,“inline”指示链接器,如果它看到该函数的不同定义,则它们都是相同的,必须合并为一个。但是忽略了这个细节,它在大多数情况下表现得就像是“static”。 - GManNickG
1
@DJ:inline 不能防止虚表查找,你需要使用调用去虚拟化来实现。 - Ben Voigt
C++标准中有没有提到这些内容? - Daniel Jour
显示剩余4条评论

31

在现代编译器上,可能没有太大区别。即使没有添加 inline 关键字也可能会进行内联,而使用 inline 关键字也不一定能实现内联。


有道理,我从参考资料和10年前的经验中得出了结论。 - Ian Fleeton

27

有区别。 https://isocpp.org/wiki/faq/inline-functions.

当你指定函数为内联函数时,你让编译器把方法的代码放到调用它的任何地方。

void myfunc() {
  square(2);
}

与...完全相同

void myfunc() {
   2 * 2;
}

调用函数有助于代码的清晰度,但当调用该函数时,本地状态必须被推送到堆栈中,为方法设置新的本地状态,并在完成后弹出先前的状态。这是很多额外开销。

现在,如果您提高优化级别,编译器将做出决策,例如展开循环或内联函数。编译器仍然可以忽略内联语句。


2
我认为使用gcc编译器时,可以使用编译标志“-Winline”来警告函数不会被内联。如果你是个受虐狂,还可以将其与“-Werror”组合使用。 - patmanpato
1
编译器仍然可以忽略inline语句。事实上,现代的每个编译器都这样做。 - val is still with Monica

6

来自维基百科上的“内联函数”

内联函数是一种编译器被要求进行内联展开的函数。

换句话说,程序员要求编译器在每个调用函数的地方插入函数的完整体,而不是生成调用函数的代码在函数定义的一个地方。编译器并不一定要遵守这个请求。


2

inline 很好地配合了 过程抽象 的概念:

inline double square (double x) { return x*x;}

int squareTwice(double x) {
    double first = square(x);
    double second = square(x);
    return first * second; 
}

以上基本类似于以下内容:
int squareTwice(double x) {
    double first = x*x;
    double second = x*x;
    return first * second; 
}

这是因为当编译器内联扩展函数调用时,函数的代码被插入到调用者的代码流中;因此,将第二个示例程序过程化抽象为第一个示例程序可能更容易一些。
过程化抽象使得将常规程序分解为更小的子程序成为可能,这样做更容易阅读(尽管这可能是一种风格选择)。

1

内联函数,如果编译器允许,将在调用它的代码中包含内联函数,就好像没有调用任何函数一样(就好像您将逻辑放在调用函数中),从而避免了函数调用开销。


6
即使使用了 inline 关键字,编译器也不一定会将函数内联。 - Marlon
1
@Alex Marlon并没有说编译器不会内联该函数,只是它不必这样做。这两件事情非常不同。 - Michael Dorst

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