代码之家  ›  专栏  ›  技术社区  ›  default

内联的目的是什么?

  •  15
  • default  · 技术社区  · 14 年前

    我有一个 discussion 具有 Johannes Schaub inline .

    namespace ... {
        static void someFunction() {
            MYCLASS::GetInstance()->someFunction();
        }
    };
    

    把它作为一个内联函数可能

    但根据我的发现 here here

    • [Inline]只有在编译器的成本/收益分析显示它是有利可图的情况下才会发生

    然而,Johannes指出,明确指定它还有其他好处。不幸的是我不理解他们。例如,他说 “inline”允许您在程序中多次定义函数。

    所以呢

    1. 只是给编译器的建议?
    2. 当你有一个小函数(我猜是1-4条指令)的时候,是否应该明确说明
    3. 内联
    4. 需要说明吗 内联

    我还缺什么吗?

    9 回复  |  直到 8 年前
        1
  •  2
  •   dirkgently    14 年前

    内联只是编译器的建议吗?

    对。

    2 说明符向实现指示函数体在调用点的内联替换 调用点的内联替换;但是,即使省略了此内联替换,其他规则 对于7.1.2定义的内联函数,仍应遵守。

    例如,来自MSDN:

    编译器将内联扩展选项和关键字视为建议。不能保证函数是内联的。您不能强制编译器内联特定函数,即使使用\uuForceInline关键字也是如此。当使用/clr编译时,如果有应用于函数的安全属性,编译器将不会内联函数。

    但请注意:

    3.2一个定义规则

    […]内联函数应在使用它的每个翻译单元中定义。

    内联函数应在使用它的每个翻译单元中定义,并应具有精确的 每种情况下的定义相同(3.2)。[注意:在调用内联函数之前可能会遇到调用 定义出现在翻译单元中。如果函数的定义出现在翻译中 在第一次声明为inline之前,程序的格式是错误的。 如果一个带有外部连接的函数 在一个翻译单元中声明内联,则应在其出现的所有翻译单元中声明内联; 无需诊断。 翻译单位。外部内联函数中的静态局部变量总是引用同一对象。 extern内联函数体中的字符串文字是不同翻译单位中的同一对象。 在extern内联函数体中定义的类型在每个转换单元中都是相同的。

    TU基本上是一组头文件加上一个实现文件( .cpp

    当你有一个小函数(I

    当然。为什么不帮助编译器帮助你生成更少的代码呢?通常情况下,如果prolog/epilog部分比内联部分花费更多的成本,那么编译器会强制生成它们吗?但你必须, 绝对必须 在开始内联之前,请阅读这篇GOTW文章: GotW #33: Inline

    是否需要内联状态以减少可执行文件 (根据维基百科[我知道,很糟糕 引用)应该找到这样的函数

    同样,正如我所说,作为一个好的程序员,你应该在可能的时候帮助编译器。但是 here's C++常见问题解答 . 所以要小心。并不是所有的编译器都做这种分析,所以您应该阅读关于它们的优化开关的文档。例如:GCC做了类似的事情:

    MSDN GCC 文件值得一读。

        2
  •  6
  •   Johannes Schaub - litb    14 年前

    重申我在那些小评论框里说的话。特别是,我从来没说过英林- :

    // foo.h:
    static void f() {
      // code that can't be inlined
    }
    
    // TU1 calls f
    // TU2 calls f
    

    现在,TU1和TU2都有自己的 f -密码 f 在可执行文件中出现两次。

    // foo.h:
    inline void f() {
      // code that can't be inlined
    }
    
    // TU1 calls f
    // TU2 calls f
    

    f 链接器通过丢弃除其中一个以外的所有对象而有效地合并的。密码 f 在可执行文件中只存在一次。

    .

        3
  •  3
  •   Loki Astari    14 年前

    内联只是编译器的建议吗?

    对。但是如果函数有多个定义,链接器就需要它(见下文)

    在头文件中定义的函数上(通常)需要它。将它添加到小函数中并没有什么坏处(但我不介意)。注意:在类声明中定义的类成员是自动内联声明的。

    内联写作还有什么好处?

    如果使用正确,它将停止链接器错误。

    即使编译器(根据wikipedia[I know,bad reference])应该自己找到这样的函数,为了减小可执行文件的大小,是否需要内联声明?

    否。编译器会对内联每个函数调用进行成本/收益比较,并做出适当的选择。因此,对一个函数的调用可能在某些情况下是内联的,而不是在其他情况下内联的(取决于编译器算法的工作方式)。

    多重定义:

    // Without inline the linker will choke.
    /*inline*/       int  add(int x, int y) { return x + y; }
    extern void test()
    

    文件:主.cpp

    #include "head.h"
    #include <iostream>
    
    int main()
    {
        std::cout << add(2,3) << std::endl;
        test();
    }
    

    #include "head.h"
    #include <iostream>
    
    void test()
    {
        std::cout << add(2,3) << std::endl;
    }
    

    这里我们有两个add()的定义。一个在main.o,一个在test.o

        4
  •  2
  •   Georg Schölly Crazy Developer    14 年前
    1. 对。没什么了。
    2. 提示编译器它是一个被调用的函数 ,其中跳转到函数部分需要大量的执行时间。 编译器可能会决定将函数代码放在调用它的位置,而不是放在普通函数的位置。但是,如果函数内联在x个位置,则需要x乘以普通函数的空间。
    3. 总是相信你的编译器在这个问题上比你自己聪明得多 微观优化。
        5
  •  2
  •   Alex F    14 年前

        6
  •  1
  •   Mhmmd    14 年前

    关于这一点:

    “inline”允许您在程序中多次定义函数。

    至于其他方面:

    1. inline #pragma 可以强制任何函数内联的指令。
    2. 因为它只是一个建议,所以显式地请求它并让编译器重写您的建议可能是安全的。但最好完全忽略它,让编译器来决定。
    3. 上面提到的混淆是内联的一个可能好处。
    4. 正如其他人所提到的, 内联 实际上会增加编译代码的大小。
        7
  •  1
  •   Hans Passant    14 年前
    1. 是的,当它认为函数太大或使用不兼容的特性(可能是异常处理)时,它很容易忽略它。此外,通常有一个编译器设置让它自动内联它认为有价值的函数(MSVC中的/Ob2)。

    2. 内联 函数放在COMDAT部分。它告诉链接器它只能从多个定义中选择一个。相当于MSVC中的uu declspec(selectany)。

    3. 内联函数通常不会使可执行文件变小。因为调用操作码通常比内联加工代码小,除了非常小的属性访问器样式的函数。这要视情况而定,但规模更大并非罕见的结果。

        8
  •  1
  •   supercat    14 年前

    in-lining的另一个好处(注意,实际的内联有时与“inline”指令的使用正交)发生在函数使用引用参数时。将两个变量传递给一个非内联函数以将其第一个操作数与第二个操作数相加,需要先推送第一个操作数的值和第二个操作数的地址,然后调用一个函数,该函数必须弹出第一个操作数和第二个操作数的地址,然后将前一个值间接地添加到弹出的地址。如果函数是内联展开的,编译器可以简单地将一个变量直接添加到另一个变量中。

        9
  •  0
  •   LennyStackOverflow    14 年前

    它是通过粘贴函数代码来减少一级间接寻址。

    http://www.parashift.com/c++-faq-lite/inline-functions.html