假设我有一些函数,每个函数大约有两行简单的代码,他们互相称呼:A
调用B
调用C
调用D
。 ..来电K
。 (所以基本上它是一系列很短的函数调用。)编译器通常会在调用树中有多深入内联这些函数?
答案 0 :(得分:13)
这个问题没有意义。
如果你考虑内联及其后果,你会意识到这一点:
在决定是否内联时,编译器会在创建的潜在膨胀和预期的速度增益之间执行平衡操作。这种平衡行为受选项影响:对于gcc -O3
意味着优化速度,而-Oz
意味着优化尺寸,内联时它们具有准相反的行为!
因此,重要的不是“嵌套级别”,而是指令的数量(可能加权,因为并非所有指令都相等)。
这意味着一个简单的转发功能:
int foo(int a, int b) { return foo(a, b, 3); }
从内联的角度来看,基本上是“透明的”。
另一方面,计算一百行代码的函数不太可能被内联。除了只调用一次的static
个自由函数是准系统内联的,因为在这种情况下它不会产生任何重复。
从这两个例子中我们可以预见到启发式行为的表现:
之后,它们是您应该能够设置为以某种方式影响的参数(MSVC为__force_inline
,强烈暗示inling,gcc
,因为它们-finline-limit
标记为“提高“指令数量等的门槛......”
在切线上:您知道部分内联吗?
它是在4.6中的gcc中引入的。顾名思义,这个想法是部分内联函数。大多数情况下,当函数被“保护”时可以避免函数调用的开销,并且可能(在某些情况下)几乎立即返回。
例如:
void foo(Bar* x) {
if (not x) { return; } // null pointer, pfff!
// ... BIG BLOC OF STATEMENTS ...
}
void bar(Bar* x) {
// DO 1
foo(x);
// DO 2
}
可以“优化”为:
void foo@0(Bar* x) {
// ... BIG BLOC OF STATEMENTS ...
}
void bar(Bar* x) {
// DO 1
if (x) { foo@0(x); }
// DO 2
}
当然,内联的启发式再次适用,但它们更适用于歧视!
最后,除非您使用WPO(整个程序优化)或LTO(链接时间优化),否则只有在定义与调用站点相同的TU(翻译单元)时才能内联函数。
答案 1 :(得分:7)
我见过编译器内联超过5个函数。但在某些时候,它基本上变成了编译器所做的空间效率权衡。每个编译器在这方面都不同。 Visual Studio非常保守,内联。 GCC(在-O3下)和英特尔编译器喜欢内联......