2010-09-12 32 views
2

我对在C和C++中使用内联函数有一些疑问。我被告知要在我经常使用的小函数上使用它,但我想明白它是如何工作的。这只是一个例子的片段。有关内联性能的问题

static inline point3D createPoint3D(float x, float y, float z){ 
    point3D newPosition; 
    newPosition.x = x; 
    newPosition.y = y; 
    newPosition.z = z; 
    return newPosition; 
} 
  1. 究竟是什么做的,为什么它有助于代码的运行速度更快?这是来自90年代的过时优化吗?

  2. 为什么我只能在小功能上使用它?如果我为大功能做了它会不好?

  3. 在大量功能上使用它不好吗?

+0

相关通知(如果您从未使用内联,则容易忘记):要在跨编译单元边界进行内联工作,必须将函数的* body *内联到标头中,而不仅仅是原型,否则当编译其他编译单元时,编译器将没有内联代码(另请参见http://www.parashift.com/c++-faq-lite/inline-functions.html#faq- 9.6)。 – 2010-09-12 22:10:57

+0

关于内联这里也有一些很好的答案:http://stackoverflow.com/questions/3647053/what-is-are-the-purposes-of-inline – Default 2010-09-12 22:27:38

+0

请注意,在C中使用'inline'完全相同与C++中的“inline”不同。后者更直接。 [见这里](http://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99)进行C讨论。 – 2015-09-15 01:49:14

回答

4
  1. 它更像是70年代或(至多)80年代的过时优化。几乎任何有能力的编译器都可以在没有任何帮助的情况下选择用于内联扩展的函数,除了启用优化之外。

  2. 它应该做的是消除调用函数的开销。对于像小功能这样的事情来说,这是非常重要的。碰巧,这些都是非常普遍的,即使在C++中实现一半的体面表现也几乎要求编译器或多或少地自动扩展内联函数。

  3. 一般毫无意义地使用它。

  4. 通常不会如上所述,当函数内联有好处时,编译器通常可以自动完成。

有两点需要注意:1)大多数编译器可以/将内联生成功能,而inline关键字,和2),如果他们考虑功能不适用于内嵌扩展大多数编译器可以/将忽略inline关键字(尽管,只是FWIW,微软有一个__forceinline来克服后者,如果你真的确定你比编译器知道得更好)。

4

请在C++ FAQ here中查看此详细信息。引用这个内联函数..

当编译器内联展开一个函数调用,该函数的代码 被插入到调用代码 流(概念上类似于 与#define宏发生)。这 可以,这取决于其他 的东西,提高性能,因为 优化程序可以程序 集成了被调用的代码 - 优化 被调用的代码到调用者。

9.3节

内联函数可能使其更快: 如上图所示,程序集成 可能会删除了一堆不必要的 指令,这可能会使事情 运行得更快。

内联函数可能会使它更慢: 过多的内联可能会导致代码 膨胀,这可能会导致“颠簸”按需分页虚拟内存 系统 。换句话说,如果 可执行文件大小过大,则系统 可能会花费大部分时间将 写入磁盘以获取下一个 代码块。

内联函数可能会使它变大: 这是代码膨胀的概念,如上面描述的 。例如,如果一个 系统有100个内联函数,其中每个 都会扩展为100个字节的 可执行代码,并在100个 位置中调用,则这将增加1MB。是 1MB会导致问题?谁知道 ,但是有可能是因为这个最后1MB会导致系统 “颠簸”,并且这可能会使事情减慢 。

内联函数可能会使它 小:编译器通常产生 更多的代码来推/流行 寄存器/参数比它会被 内联展开函数体。 这种情况非常小 功能,并且也恰好与 大型活动时,优化器 能够通过程序的整合,以除去大量的冗余代码 - 即 ,当优化器能够使 大功能小。

内联函数可能导致 抖动:内联可能会增加 大小的二进制可执行文件,并 可能会导致系统性能下降。

内联函数可能防止 抖动:工作集大小 (那需要在 内存一次页数)可能会往下走,即使 可执行文件的大小上升。当f() 调用g()时,代码通常在两个不同的页面上;当编译器 将代码 g()过程集成到f()中时,代码通常在 的同一页上。

内联函数可能增加 数高速缓存未命中:内联可能会导致 内环到跨越存储器的高速缓存, 的 多行跨越和可能导致 内存的缓存的抖动。

内联函数可能降低 数高速缓存未命中:内联 通常会提高的二进制代码,这可能会降低 的存储内 循环的代码所需要的高速缓存行 数内参考 局部性。这最终可能会导致CPU限制应用程序运行得更快。

内联函数可能不相关 加速:大多数系统不是 受CPU限制的。大多数系统是I/O绑定的,数据库绑定的或网络绑定的 , 意味着系统的 整体性能的瓶颈是文件 系统,数据库或网络。 除非您的“CPU计量器”与 100%挂钩,否则内联函数可能不会 使您的系统更快。 (即使在 CPU受限的系统,内嵌有利于 瓶颈 本身内使用时,才和瓶颈 通常只有一小部分的代码 。)

有没有简单的答案:你有 玩它看看什么是最好的。 不要满足于简单的答案 一样,“不要使用内联函数”或 “始终使用内联函数”或“使用 内联函数,当且仅当 功能不足的 N行代码。”这些一刀切的规则 可能很容易写下来,但他们 将产生次优结果。

+0

因此,如果我不关心文件大小,我可以在任何事情上尽可能多地使用它? – 2010-09-12 22:13:25

2

inline关键字表示您认为此函数是包含代替对该函数的调用的良好候选者。它最适用于功能较小的功能,因为它的每次使用都会将功能体的新副本放在使用位置。过度使用可能会大大增加调用代码的大小。

这很有价值,因为有时候优化器可以在一个小函数中看到更好的工作。通过内联函数体,优化器获得了这个机会。它还提高了执行线程的引用的局部性,可以提高指令缓存和管道的性能。

在经典的C语言中,获得这种效果的唯一方法是使用宏,但是宏具有明显的缺点,即它们是纯文本替换,因此它们会在每次出现它们时都会评估它们的每个参数在替换文本中。如何安全地允许宏具有局部变量也是非显而易见的。

在C++中,通常允许作为该语言的常用习惯用法的小型存取器函数内联,以至于在类定义中定义其体的函数被隐式标记为inline

一个好的优化器会自行决定何时实际使用内联函数以及何时正常调用函数,因此通常不会对将函数自由标记为inline有太大不利影响。

3

不用担心。 直到你测量完全一样。一旦你测量,你将不会注意到与编译ot没有inline版本之间的巨大差异。

1)inline建议给编译器直接在代码流中“内联”函数,而不是“调用”它。这绕过设置堆栈的需要,并做其他杂务需要调用功能

 
     NOT INLINE     INLINE 
     ...       ... 
     code       code 
     call fx -\     code from fx 
     code  |     code from fx 
     call fx --|     code from fx 
     ...   |     code 
        |     code from fx 
     code <------/     code from fx 
     ...       code from fx 
     return      ... 

2)在任何你想要的地方使用它。编译器很可能会忽略你的建议

3)同2)

4)措施。实验和比较