函数所需的总堆栈大小如何与变量作用域相关

How is total stack size required by a function and variable scope related?

本文关键字:变量 作用域 堆栈 函数      更新时间:2023-10-16

我得到一个堆栈溢出在我的程序正在与Visual Studio 2010编译。我有一个宏,在do-while块内,使用堆栈上分配的小字符数组(8 KiB)做一些字符串相关的工作。然后我有一个函数,我在同一个作用域中多次使用这个宏。现在我得到堆栈溢出

我假设堆栈分配是do-while块的局部,因此当块结束时,数组将不再存在,因此不会对函数的整体堆栈使用做出贡献,但似乎我错了。

使用调试器,我能够看到在输入函数时,_chkstk()被调用。作为该函数的参数,堆栈大小略大于该函数中每次宏调用的所有8个KiB数组的总和(由于其他局部变量的影响,堆栈大小略大)。

我用一个简单的例子重现了这个问题:

void func(void)
{
    {char a[500000];}
    {char b[500000];}
    {char c[500000];}
    {char d[500000];}
    {char e[500000];}
}

在一个简单的控制台应用程序中,从main()调用这个函数将导致堆栈溢出。然而,删除除一条语句外的所有块语句将正常运行。

我想知道这是否按预期工作?

如何计算函数所需的总堆栈大小?如何计算函数所需的堆栈大小?堆栈上的数组仍然对函数的总堆栈大小有贡献,即使在超出作用域之后?

为什么当

我很确定标准没有确切定义这些变量需要多少堆栈空间(或者实际上它们存储在堆栈上)。编译器当然不需要为每个局部变量分配空间。实际的重用也可能高度依赖于编译器的优化级别——因此,如果使用不同级别的优化进行编译(或者启用/禁用某些优化特性),它可能会做不同的事情。

在c++中,对构造函数和析构函数的调用是为包含变量的块定义的,因此如果您要使用std::vector,则在块结束时释放内存(从堆中分配)。

总而言之:空间可以被重用,但这并不能保证。

我想这是特定于编译器的。在GCC中也可以很好地工作:数组在超出作用域后从堆栈中删除(但是当所有数组属于同一块时,它会抛出段错误)。