C ++函数内联意味着什么?

时间:2008-10-01 06:25:18

标签: c++ inline-functions

参见标题:C ++函数内联是什么意思?

9 个答案:

答案 0 :(得分:35)

该函数放在代码中,而不是被调用,类似于使用宏(概念上)

这可以提高速度(没有函数调用),但会导致代码膨胀(如果函数使用了100次,那么现在有100个副本)

你应该注意这并没有强制编译器使函数内联,如果它认为这是一个坏主意它会忽略你。类似地,编译器可能决定为您内联正常函数。

这也允许你将整个函数放在一个头文件中,而不是在一个cpp文件中实现它(你无论如何都不能这样做,因为如果它被声明为内联,你会得到一个未解析的外部,除非当然只有那个cpp文件使用它。)

答案 1 :(得分:26)

这仅仅意味着一件事:编译器将忽略函数的多个定义。

通常不能多次定义函数(即,如果将非内联函数定义放入标题中,然后将#include到多个编译单元中,则会收到链接器错误)。将函数定义标记为“内联”可以抑制此错误(链接器可确保正确的事情发生)。

它并不意味着更多!

最重要的是,它并不意味着编译器会将编译的函数嵌入到每个调用站点中。这是否完全取决于编译器的奇思妙想,并且内联修饰符通常很少或根本没有改变编译器的思想。编译器可以 - 并且确实 - 标记为内联的内联函数,并且它可以对 标记为内联的函数进行函数调用。

要记住多个定义是值得记住的。

答案 2 :(得分:20)

除了关于inline的性能影响的其他(完全正确)答案之外,在C ++中你还应该注意到这可以让你安全地将函数放在标题中:

// my_thing.h
inline int do_my_thing(int a, int b) { return a + b; }

// use_my_thing.cpp
#include "my_thing.h"
...
    set_do_thing(&do_my_thing);

// use_my_thing_again.cpp
...
    set_other_do_thing(&do_my_thing);

这是因为编译器只在第一个目标文件中包含函数的实际主体,需要编译常规可调用函数(通常是因为它的地址已被采用,如上所示)。

如果没有inline关键字,大多数编译器会给出有关多个定义的错误,例如对于MSVC:

use_my_thing_again.obj : error LNK2005: "int __cdecl do_my_thing(int,int)" (?do_my_thing@@YAHHH@Z) already defined in use_my_thing.obj
<...>\Scratch.exe : fatal error LNK1169: one or more multiply defined symbols found

答案 3 :(得分:3)

@OldMan

  

只有在您要求内联函数执行此操作时,编译器才会将内联非标记为内联函数。

只有“请求”是指“开启优化”。

  

它只对卡斯特的效果是正确的。

两者都是正确的。

  

内联不会生成链接器可能使用的任何额外信息。 Compiel 2对象文件并检查。它允许多个定义,因为符号不会导出!不是因为那是它的目标!

你是什么意思,“这些符号不会被导出”?内联函数不是静态的。他们的名字是可见的;他们有外部联系。引用C ++标准:

  

void h();   inline void h(); //外部链接

     

inline void l();   void l(); //外部链接

多重定义是非常重要的目标。这是强制性的:

  

内联函数应在每个使用它的翻译单元中定义,并且应具有完全相同的内容   每种情况下都有相同的定义(3.2)。 [注意:在定义之前可能会遇到对内联函数的调用   出现在翻译单元中。 ]如果在一个转换中内联声明了具有外部链接的函数   单位,应在其出现的所有翻译单位内联;无需诊断。一个   具有外部链接的内联函数在所有翻译单元中应具有相同的地址。

答案 4 :(得分:2)

函数体实际上插入了调用函数中。因此,如果您有多次调用此函数,则会获得代码的多个副本。好处是您可以更快地执行。

通常非常短的函数被内联,当函数体的副本不会比为正常函数调用生成的通常的序言/结尾代码大很多时。

您可以在MSDN上有关内联的文章中阅读更多内容 - http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx

答案 5 :(得分:1)

内联函数可能会生成放置在应用程序代码段中的指令,从而改变应用程序的性能配置文件。是否内联函数由编译器决定。根据我的经验,大多数现代编译器都善于确定何时符合用户的内联请求。

在许多情况下,内联函数将改善其性能。函数调用存在固有的开销。然而,有理由说明为什么内联函数可能是负面的:

  • 通过复制代码来增加二进制可执行文件的大小可能会导致磁盘抖动,从而降低应用程序的速度。
  • 内联代码可能会导致缓存未命中,或者可能会导致缓存命中,具体取决于您的体系结构。

C ++ FAQ可以很好地解释关键字的复杂性: http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.3

答案 6 :(得分:0)

非正式地,这意味着允许编译器将函数的内容移植到调用站点上,这样就没有函数调用。如果您的函数具有大的控制语句(例如,ifswitch等),并且可以在编译时在调用站点评估条件(例如,在调用站点使用的常量值),然后你的代码会变得更小(未使用的分支被删除)。

更正式地说,内联函数也有不同的联系。我会让C ++专家谈论这个方面。

答案 7 :(得分:0)

调用函数会对CPU产生一定的性能损失,而不仅仅是具有线性指令流。 CPU的寄存器必须写入另一个位置等。显然,具有功能的好处通常超过性能损失。但是,在性能成为问题的地方,例如传说中的“内部循环”函数或其他一些瓶颈,编译器可以将函数的机器代码插入到主要的执行流中,而不是通过CPU的税来调用函数

答案 8 :(得分:0)

编译器允许您标记为内联的函数。无法保证compielr会这样做。编译器本身使用复杂的语义来设置何时执行或不执行。

当编译器决定应该内联函数时,调用者代码中对函数的调用将被calee的代码替换。这意味着您可以节省堆栈操作,调用本身并改善代码缓存的位置。有时这可能会带来巨大的性能提升。特别是在1行数据访问函数中,如面向对象代码中使用的访问器。

成本通常会导致更大的代码,可能会影响性能。这就是为什么将函数设置为内联只是编译器的“绿色标志”,它不需要遵循。编译器将尝试做最好的事情。

作为不想处理连锁特性的初学者的经验法则。内联函数将由相同编译单元中的其他函数调用。如果要实现可在多个编译单元上使用的内联函数,请将其声明为头文件并实现内联函数。

为什么?

示例:at header file inlinetest.h

int foo();
inline int bar();

在编译单元inlinetest.cpp

 int foo(){ int r = bar(); return r; }


 inline int bar(){ return 5;};

然后在main.cpp

 #include "inlinetest.h"
 int main()
 {
  foo();
 //bar();
  }

一次编译一个目标文件。如果取消注释“bar”调用,则会出错。因为内联函数仅在inlinetest.o对象文件中实现,因此不会导出。同时foo函数,很可能已经嵌入了bar函数的代码(因为bar是单行无I / O操作然后它很可能被内联)

但是如果在头文件中你声明了内联函数并将其实现为内联,那么你就可以在任何包含该头的编译单元中使用它。 (“代码样本”);

删除内联关键字和编译器即使在main处调用bar也不会导致错误除非您要求编译器内联所有函数,否则不会发生内联。这不是大多数编译器的标准行为。