我对C ++中的inline
函数有疑问。我知道类似的问题多次出现在此。我希望我的有点不同。
我知道当你指定某个函数为inline
时,它只是一个"建议"到编译器。所以:以防万一:
inline int func1()
{
return 2;
}
稍后的一些代码
cout << func1() << endl; // replaced by cout << 2 << endl;
所以那里没有神秘感,但是这样的情况呢:
inline int func1()
{
return 2;
}
inline int func2()
{
return func1() * 2;
}
inline int func3()
{
return func2() * func1() * 2;
}
等等......
哪些功能有机会内联,是否有益以及如何检查编译器实际执行的操作?
答案 0 :(得分:4)
其中哪些功能有机会成为内联
如果执行内联的工具(1)可以访问函数的定义(= body),则任何和所有函数都有可能被内联...
有益吗
......并认为这样做很有帮助。如今,优化器的工作是确定内联在哪里是有意义的,对于99.9%的程序,程序员可以做的最好的事情就是远离优化者的方式。剩下的几个案例是像Facebook这样的程序,其中0.3%的性能损失是巨大的回归。在这种情况下,手动调整优化(以及分析,分析,和分析)是可行的方法。
如何检查编译器实际执行的操作
通过检查生成的组件。每个编译器都有一个标志,使其输出汇编在&#34;人类可读&#34;格式而不是(或除了)二进制形式的目标文件。
(1)通常,此工具是编译器,内联作为编译步骤的一部分(将源代码转换为汇编/目标文件)。这也是您可能需要使用inline
关键字实际允许编译器内联的唯一原因:因为函数的定义必须在正在编译的转换单元(=源文件)中可见,通常这意味着将函数定义放入头文件中。如果没有inline
,如果头文件包含在多个翻译单元中,则会导致多重定义错误。
请注意,编译不是可以进行内联的唯一阶段。启用整体程序优化(也称为链接时代码生成)时,一旦创建了所有目标文件,就会在链接时再发生一次优化。此时,inline
关键字完全无关紧要,因为链接可以访问所有函数定义(否则二进制文件不能成功链接)。因此,这是 从内联中获得最大收益的方式,而不必在编写代码时考虑它。缺点是时间:WPO需要时间来运行,对于大型项目,可能会将链接时间延长到不可接受的水平(我个人经历了一个有点病态的情况,即启用WPO从7分钟开始程序的链接时间至46)。
答案 1 :(得分:1)
将inline
视为编译器的提示,在旧版本的C ++和C标准中有点像register
。警告,register
正在废弃(在C ++ 17中)。
哪些功能有机会内联,是否有益
信任您的编译器,以制定理智的内联决策。要启用某些特定的调用,编译器需要知道被调用函数的主体。您不应该关心编译器是否在线(理论上)。
实际上,使用GCC编译器:
inlining并不总能改善效果(例如,由于CPU cache问题,TLB,branch predictor等等......)
内联决策取决于optimization options上的 lot 。 -O3
可能比-O1
更可能发生;有很多大师选项(如-finline-limit=
和其他)可以调整它。
请注意,个别来电是否内联。第123行的foo(x)
之类的调用很可能是内联的,但是另一次调用(对于相同的函数foo
),例如foo(y)
像456行这样的其他地方没有内联。
当调试时,您可能想要禁用内联(因为这样可以使调试更方便)。这可以通过-fno-inline
GCC优化标志(我经常与-g
一起使用,它会询问调试信息)。
always_inline
function attribute&#34;部队&#34;内联,noinline
阻止它。
如果您使用链接时间优化(LTO)编译并链接,例如-flto -O2
(或-flto -O3
),例如在CXX=g++ -flto -O2
中使用Makefile
,可以在多个翻译单元(例如C ++源文件)之间进行内联。但是,LTO至少会使编译时间翻倍(通常情况下更糟)并在编译期间消耗内存(因此更好地拥有大量RAM),并且通常只会提高几个百分点的性能(这个经验法则有奇怪的例外)
您可能会以不同方式优化功能,例如with #pragma GCC optimize ("-O3")
或function attribute optimize
同时查看profile-guided optimizations instrumentation options,-fprofile-generate
,-fprofile-use
,g++ -O2 -S -fverbose-asm
与其他optimization flags进行优化。
如果您对内联的调用感兴趣(有时候,有些人不会)查看生成的汇编程序(例如使用.s
并查看.border-top-0{
border-style: solid;
border-top: none;
}
汇编程序文件),或使用一些内部dump options。
代码的可观察行为(性能除外)不应该依赖于编译器的内联决策。换句话说,不要期望内联发生(或不发生)。如果您的代码在有或没有优化的情况下表现不同,则可能是错误的。请阅读undefined behavior。
另见MILEPOST GCC项目(使用机器学习技术进行优化)。