c++ - 编译器内联函数有多深?

标签 c++ function compiler-construction inline

假设我有一些函数,每个函数大约有两行简单的代码,它们相互调用如下: A 调用 B 调用 C 调用 D ... 调用 K。 (所以基本上这是一连串的短函数调用。)编译器通常会在调用树中内联这些函数的深度是多少?

最佳答案

这个问题没有意义。

如果您考虑内联及其后果,您就会意识到:

  • 避免函数调用(所有寄存器保存/帧调整)
  • 向优化器公开更多上下文(死存储、死代码、公共(public)子表达式消除...)
  • 重复代码(膨胀指令缓存和可执行文件大小等)

在决定是否内联时,编译器会在产生的潜在膨胀和预期的速度增益之间进行平衡。这种平衡行为受选项影响:对于 gcc,-O3 表示优化速度,而 -Oz 表示优化大小,在内联时它们具有准相反的行为!

因此,重要的不是“嵌套级别”,而是指令的数量(可能加权,因为并非所有的都是平等的)。

这意味着一个简单的转发函数:

int foo(int a, int b) { return foo(a, b, 3); }

从内联的角度来看基本上是“透明的”。

另一方面,计算一百行代码的函数不太可能内联。除了只调用一次的 static 自由函数是准系统内联的,因为在这种情况下它不会产生任何重复。

从这两个示例中,我们可以预知启发式的行为方式:

  • 函数的指令越少,内联效果越好
  • 调用越少,内联效果越好

之后,它们是您应该能够设置以影响一种或另一种方式的参数(MSVC as __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(翻译单元)中时才能内联函数。

关于c++ - 编译器内联函数有多深?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7463034/

相关文章:

java - 如何在 Vector Java 的 Vector 中查找(打印)指定字段

c++ - C 编译器如何处理使用未初始化的变量?

delphi - 如何强制Delphi编译器显示所有提示和警告

c++ - 使用 Wfloat-equal 选项将 float 与 1 或 0 进行比较

c++ - VS2010 : Set what directory an executable looks for files in

R 获取函数参数的名称

arrays - 从 Bash 函数返回数组

c - 需要大型 C99 测试文件

c++ - 如果使用较小的数字,switch case 会更快吗?

c++ - 更改 CMFCListCtrl 的默认排序箭头