编译器是否优化了内联函数的局部变量
Does compiler optimize inline function's local variables
现在我正在阅读Inside The C++ Object Model
这本书的第四部分,并有一些问题。
像这样的内联函数:
inline int max(int a, int b)
{
return (a > b) ? a : b;
}
然后,一个如下的语句:a = max(x, y);
该语句将转换为a = (x > y) ? x : y;
但书中说,当向内联函数添加局部变量时,如下所示:
inline int max(int a, int b)
{
int maxval = (a > b) ? a : b;
return maxval;
}
它将转变为
int __max_lv_maxval;
a = (__max_lv_maxval = (x > y) ? x : y), __max_lv_maxval;
很明显,该功能的性能会下降。
我的问题是编译(如VC2010、gcc)是否优化了内联函数并删除了局部变量?
这本书似乎假设编译器在源代码级别内联,这当然完全取决于编译器。大多数都将在AST级别开始内联,在那里可以并且将发生转换和某些优化。这一切都假设编译器将内联代码。
如果我们查看您的函数,任何像样的编译器都会将它们转换为相同的IR代码,因为它会在内联函数之前对其进行编译,因此无论何时(在IR级别)都需要临时的。当IR被实际内联时,临时将被折叠起来,取而代之的是调用max
的分配目的地。
当我们编译到机器代码时,情况可能会发生更大的变化,不仅可以删除临时性,而且目标很可能是一个寄存器(在这种情况下),它可能也会用于任何源操作数。
底线:这完全取决于您的编译器、优化级别以及它如何进行变量活泼性分析、值传播和折叠。
我们可以对代码进行任何有趣的转换,编译器也可以。然后是一些!
当编译器可以看到
inline int max(int a, int b)
{
return (a > b) ? a : b;
}
a = max(x, y);
可以转换为
a = (x > y) ? x : y;
它还可以很容易地看出,将值存储到以后再也不用的变量中是没有意义的。存储(和变量)可以在不更改程序结果的情况下删除。
小函数中的局部变量通常保存在CPU寄存器中,根本不会存储在内存中。
inline int max(int a, int b) { return (a > b) ? a : b; }
然后,一个语句如下:
a = max(x, y);
该语句将转换为
a = (x > y) ? x : y;
事情没那么简单。inline
是一个提示,而不是一个要求。关键字确实会稍微更改规则,但不会强制内联。你还忘记了a
和b
也是max
函数的局部变量,而假设局部变量不能被优化掉的同一本书假设这些局部变量可以被优化掉。在安全的情况下,它们可能会被优化掉,也可能不会,这取决于编译器和编译器选项。对于在调试器中运行,保留它们可能更有意义。当这样做不安全时,例如当x
和y
是volatile
时,它们可能而不是被优化掉。在这种情况下,(x > y) ? x : y
读取其中一个两次,这是一种潜在的可见行为变化,因此是无效的。
编译器就像您展示的那样。如果我们把这个内联称为有趣的
void example()
{
int m = max(10, 11);
}
扩展将是
{
int __max_lv_maxval;// mangled inline local variable
int m = (__max_lv_maxval = (x > y) ? x : y), __max_lv_maxval;
}
通常,内联函数中的每个局部变量都必须引入到调用的封闭块中作为唯一命名的变量。海湾合作委员会不会为你做更多的事情。
- 局部变量保留函数中的值
- 如何使用 C++ 中的继承函数访问派生类中的局部变量
- 如何在函数外部访问函数中局部变量的值?
- 赋予全局变量而不是局部变量优先级的函数 - (异常行为)
- 获取具有静态局部变量的绑定/推断捕获 lambda 的函数指针
- 函数局部静态变量:从性能角度来看的优点/缺点
- 是否可以影响 C++ 中回调函数的局部变量?
- 将共享指针传递给函数参数 - 将其分配给局部变量的正确方法是什么
- 调用一个小函数两次(例如在if条件和主体中)比将结果存储在局部变量中更可取
- C++ - 指向函数中局部变量的指针
- 如何在 C++ 的 lambda 函数中传递同名的局部变量和参数(使用此关键字)?
- Clang++ 6.0 内存清理器未报告返回值指示条件分支的函数中的未初始化局部变量
- 如何将局部变量传递给 lambda 函数
- 局部变量的作用域是块或函数
- 函数原型未初始化的局部变量
- 尝试声明函数的局部变量,但得到范围错误
- 为什么堆栈中的函数局部变量之间存在内存空间
- 返回函数局部变量作为引用
- 函数局部变量在函数调用之间保持不变
- 对静态函数局部变量的引用