我试图更好地理解C语言中的块作用域,以及该标准是否提供有关退出块作用域时弹出堆栈元素的任何保证,而这些保证可能在进入该作用域时已被推送到堆栈中。例如,在该块内声明了变量之后,跳转到块外的标签(就是,跳转到C中的标签,那里没有什么特别的东西)是否会导致堆栈损坏?
这是一个人为的示例,如果有助于进一步定义问题,请假设-O0
。我的困惑是,当跳转到err2
标签的执行路径被击中时,是否从堆栈中弹出fatal
。因为标签在C中没有什么特别的,所以我假设err2
不会从堆栈中弹出,并且会导致堆栈损坏。
void foo()
{
int err;
if (err = baz()) {
printf("error %i", err);
int err2;
if (err2 = another_thing())
goto fatal;
}
printf("done");
return;
fatal:
printf("there was a fatal error");
}
答案 0 :(得分:4)
无法肯定地回答;但是大多数编译器会一次为该函数分配所有内存。
实际上,如果超出范围,访问指向它的指针是一个坏主意,否则您将不在乎。即使在-O0
,范围外变量的内存也可能会被重用。
在任何情况下,局部变量都不会泄漏。堆栈不会变得不平衡。问题中的代码中没有任何危险。
答案 1 :(得分:1)
在使用GCC或MSVC的基于堆栈的处理器(如x86)的情况下,无论作用域如何,所有本地变量的堆栈空间都将在输入函数foo
时保留。不论到达出口的方式如何,退出时都会释放堆栈框架,从而回收堆栈空间。
对于C ++,情况则有所不同。不是您的示例,但是如果您跳过构造函数,则该构造函数将不会运行,但是编译器仍将运行析构函数,这将导致混乱。幸运的是,正如Joshua在评论中指出的那样,现代编译器会检测到这种情况,并将生成编译时错误以避免这种情况。