内联函数(何时插入)?

时间:2009-08-13 11:14:10

标签: c++

内联函数只是对编译器的请求,这些编译器在使用该函数的代码中的每个位置插入内联函数的完整主体。

但是编译器如何决定是否应该插入它?它使用哪种算法/机制来决定?

谢谢,

纳温

7 个答案:

答案 0 :(得分:4)

一些常见方面:

  • 编译器选项(调试版本通常不内联,大多数编译器都有覆盖内联声明以尝试内联所有内容的选项,或者没有内容)
  • 合适的调用约定(例如,varargs函数通常不内联)
  • 适合内联:取决于函数的大小,函数的调用频率,内联增益和优化设置(速度与代码大小)。通常,微小的函数具有最大的好处,但如果只调用一次
  • ,则可以内联一个巨大的函数
  • 内联调用深度和递归设置

第三个可能是你问题的核心,但这确实是“编译器特定的启发式” - 你需要检查编译器文档,但通常它们不会提供太多保证。 MSDN有一些(有限的)MSVC信息。

除了琐事(例如简单的getter和非常原始的函数)之外,内联不再是非常有用的了。呼叫指令的成本已经下降,并且分支预测已经大大改善。

内联的绝佳机会是删除编译器知道不会采用的代码路径 - 作为一个极端的例子:

inline int Foo(bool refresh = false)
{
   if (refresh)
   {
      // ...extensive code to update m_foo  
   }
   return m_foo;
}

一个好的编译器会内联Foo(false),而不是Foo(true)

使用链接时间码生成,Foo可以驻留在.cpp(没有inline声明)中,Foo(false)仍然会内联,所以内联再次只有边际效应


总结:在极少数情况下,您应尝试通过放置(或省略)内联语句来手动控制内联。

答案 1 :(得分:2)

我对内联函数(以及许多其他c ++内容)的所有了解都是here

另外,如果你专注于每个编译器的启发式方法来决定是否有函数,那么这依赖于实现,你应该看看每个编译器的文档。请记住,启发式也可能会根据优化级别而改变。

答案 2 :(得分:2)

以下是Sun Studio 11编译器的FAQ

  

当满足以下任何条件时,编译器会将内联函数生成为普通的可调用函数(不在线):

     
      
  • 使用+ d。
  • 进行编译   
  • 使用-g。
  • 进行编译   
  • 需要函数的地址(与虚函数一样)。
  •   
  • 该函数包含编译器无法内联生成的控制结构。
  •   
  • 功能过于复杂。
  •   

根据'clamage45'对此post的响应,“编译器无法生成内联的控制结构”是:

  
      
  • 该函数包含禁用的构造,如loop,switch或goto
  •   

可以找到另一个列表here。正如大多数其他答案所指定的那样,启发式算法将是100%编译器特定的,从我所读到的,我认为确保函数实际内联,你需要避免:

  • 本地静态变量
  • 循环结构
  • switch statements
  • 尝试/捕获
  • 转到
  • 递归
  • 当然太复杂(无论这意味着什么)

答案 3 :(得分:1)

我很确定大多数编译器根据函数的长度(编译时)以字节为单位决定使用频率与优化类型(速度与大小)的比较。

答案 4 :(得分:1)

我只知道几个标准:

  • 如果内联遇到递归 - 内联将被忽略。
  • switch / while / for在大多数情况下导致编译器忽略内联

答案 5 :(得分:1)

这取决于编译器。这是GCC手册所说的(第一部分):

    -finline-limit=n
           By default, GCC limits the size of functions that can be inlined.
           This flag allows the control of this limit for functions that are
           explicitly marked as inline (i.e., marked with the inline keyword
           or defined within the class definition in c++).  n is the size of
           functions that can be inlined in number of pseudo instructions (not
           counting parameter handling).  The default value of n is 600.
           Increasing this value can result in more inlined code at the cost
           of compilation time and memory consumption.  Decreasing usually
           makes the compilation faster and less code will be inlined (which
           presumably means slower programs).  This option is particularly
           useful for programs that use inlining heavily such as those based
           on recursive templates with C++.

           Inlining is actually controlled by a number of parameters, which
           may be specified individually by using --param name=value.  The
           -finline-limit=n option sets some of these parameters as follows:

            @item max-inline-insns-single
             is set to I/2.
            @item max-inline-insns-auto
             is set to I/2.
            @item min-inline-insns
             is set to 130 or I/4, whichever is smaller.
            @item max-inline-insns-rtl
             is set to I.

           See below for a documentation of the individual parameters
           controlling inlining.

           Note: pseudo instruction represents, in this particular context, an
           abstract measurement of function's size.  In no way, it represents
           a count of assembly instructions and as such its exact meaning
           might change from one release to an another.

答案 6 :(得分:-2)

如果你在函数的开头写“内联”,它会插入吗?