现在我读了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)是否优化了内联函数并删除了局部变量?
答案 0 :(得分:6)
这本书似乎假设编译器在源代码级别内联,这当然完全取决于编译器。大多数将开始在AST级别内联,其中转换和某些优化可以并且将发生。这都假定编译器将内联代码。
如果我们查看你的函数,任何体面的编译器都会将它们变成相同的IR代码,因为它会在内联之前编译内联函数,因此无论如何都需要临时函数(at IR级别)。当IR实际内联时,临时折叠将被折叠,而是替换为max
调用的分配目的地。
当我们编译成机器代码时,事情可能会发生更大的变化,不仅可以删除临时值,而且目标很可能是一个寄存器(在这种情况下),它可能已用于源代码操作数也是如此。
底线: 这完全取决于您的编译器,优化级别以及它如何进行变量生动性分析,值传播和折叠。
答案 1 :(得分:1)
我们可以对代码做任何有趣的转换,编译器也可以做。然后一些!
当编译器可以看到
时inline int max(int a, int b)
{
return (a > b) ? a : b;
}
a = max(x, y);
可以转化为
a = (x > y) ? x : y;
还可以很容易地看到将值存储到以后从未使用过的变量中是没有意义的。可以删除商店(和变量)而不更改程序的结果。
小函数中的局部变量通常保存在CPU寄存器中,并且从不存储在内存中。
答案 2 :(得分:1)
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
会将其中一个读取两次,这可能会导致行为发生变化,因此无效。
答案 3 :(得分:-1)
编译器就像你展示的一样。 如果我们这样称之为内联乐趣
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;
}
通常,必须将内联函数中的每个局部变量引入到调用的封闭块中 作为唯一命名的变量。海湾合作委员会不会为你做更多的事情。