为什么在 C++ 中为执行线程从未遇到过的局部变量声明分配堆栈空间?或者,如果 C++ 标准未定义,为什么某些编译器为执行线程从未遇到的局部变量声明分配堆栈空间?编译器能否只为执行线程遇到的变量声明分配堆栈空间并且仍然可以工作?
为了说明,在无法遇到变量字符的调试模式下调用此函数会导致堆栈溢出:
void f()
{
if (false)
{
char chars[INT_MAX];
}
}
为什么在 C++ 中为执行线程从未遇到过的局部变量声明分配堆栈空间?或者,如果 C++ 标准未定义,为什么某些编译器为执行线程从未遇到的局部变量声明分配堆栈空间?编译器能否只为执行线程遇到的变量声明分配堆栈空间并且仍然可以工作?
为了说明,在无法遇到变量字符的调试模式下调用此函数会导致堆栈溢出:
void f()
{
if (false)
{
char chars[INT_MAX];
}
}
编译器提升了局部变量的声明。是否这样做没有由标准定义,因此行为是特定于实现的。这样做可以一次为所有局部变量分配空间,从而减少开销。
但是,通过优化,编译器会将您的特定情况识别为死代码,并且您遇到的情况将被消除。
1)没有理由不这样做。C++ 标准不保证在执行期间未进入范围内的变量不会为它们分配空间。
2)它更快更简单。如果一次分配所有局部变量,则为局部变量分配空间的代码包括在函数开头对堆栈指针的一次更新,以及在结尾处的一次更新。如果一个范围内的局部变量必须在该范围的开始和结束时被分配和释放,你会得到更多的堆栈指针更新。
这将非常依赖于编译器和优化级别。一些编译器能够判断那里的 if 块永远不会到达,因此根本不会为它发出代码。其他人会。其他可能取决于优化级别。还有一些人在调用函数时为所有局部变量分配空间,而不是在输入范围时分配空间,因为计算起来“更简单”。这实际上类似于 vanilla C 的行为,因为您必须在函数的开头声明所有变量(不确定 vanilla C 中是否存在带有作用域局部变量的封闭作用域,已经很长时间了),所以它可能是一个保留从此。
此外,您显然会遇到堆栈远小于堆,以及局部变量声明如何超出其容量,但我很确定这是您示例的意图。
如果您正在寻找更好的“他们为什么这样做”,请发布您为此使用的编译器版本(和设置),也许其中一位创建者会做出回应。没有那个,谁知道呢?
在 MSVC 的情况下,未使用的局部变量会发出编译器警告 (C4101)。更多详情请访问:http: //msdn.microsoft.com/en-us/library/c733d5h9 (v=vs.80).aspx
这取决于编译器和您使用的设置。例如(我必须对其进行修改,以便它实际上可以在 VS 2008 中编译),以下将在 Debug 中引发堆栈溢出异常,但在 Release 中完成:
void f()
{
if (false)
{
char chars[INT_MAX/2];
}
}
int main(int argc, _TCHAR* argv[])
{
f();
return 0;
}