我正在尝试更好地理解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");
}
无法肯定回答;但是大多数编译器会立即为函数分配所有内存。
实际上,如果它超出范围,访问指向它的指针是一个坏主意,否则你不在乎。即使在-O0
,也可以重用超出范围的变量的内存。
在任何情况下,局部变量都不会泄漏。堆栈不会变得不平衡。问题中的代码没有任何危险。
在使用GCC或MSVC的基于堆栈的处理器(如x86)的情况下,所有本地的堆栈空间,无论范围如何,都将在进入函数foo
时保留。无论出口是如何到达的,堆栈帧将在退出时展开,并按预期回收堆栈空间。
但对于C ++,情况则有所不同。不完全是你的例子,但是如果你跳过一个构造函数,那么构造函数就不会运行,但是编译器仍会运行析构函数,这会导致混乱。幸运的是,正如Joshua在评论中指出的那样,现代编译器会检测到这种情况,并会产生编译时错误以避免这种情况。