在 C 中的块范围内的变量声明之后使用 goto
Using goto after a variable declaration at block scope in C
我试图更好地理解 C 中的块作用域,以及该标准是否提供关于在退出块作用域时弹出堆栈元素的任何保证,这些元素在进入该作用域时可能已被推送到堆栈。例如,在该块内声明变量后跳转到块外的标签(这只是,好吧,跳转到 C 中的标签,那里没什么特别的)会导致堆栈损坏吗?
这是一个人为的例子,如果它有助于进一步定义问题,假设 -O0
。我的困惑是当跳转到 fatal
标签的执行路径被击中时, err2
是否从堆栈中弹出。因为标签在 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
,范围外变量的内存也可能被重用。
在任何情况下都不会泄漏局部变量。堆栈不会变得不平衡。问题中的代码没有任何危险。
在像 x86 这样使用 GCC 或 MSVC 的基于堆栈的处理器的情况下,所有局部变量的堆栈 space,无论范围如何,都将在函数 foo
的入口处保留。堆栈框架将在退出时展开,并按预期回收堆栈 space,而不管如何到达出口。
然而,对于 C++,情况有所不同。不完全是您的示例,但是如果您跳过构造函数,则构造函数将没有 运行 但是编译器仍将 运行 析构函数,这会导致混乱。幸运的是,正如 Joshua 在评论中指出的那样,现代编译器会检测到这种情况,并会生成编译时错误来避免这种情况。
我试图更好地理解 C 中的块作用域,以及该标准是否提供关于在退出块作用域时弹出堆栈元素的任何保证,这些元素在进入该作用域时可能已被推送到堆栈。例如,在该块内声明变量后跳转到块外的标签(这只是,好吧,跳转到 C 中的标签,那里没什么特别的)会导致堆栈损坏吗?
这是一个人为的例子,如果它有助于进一步定义问题,假设 -O0
。我的困惑是当跳转到 fatal
标签的执行路径被击中时, err2
是否从堆栈中弹出。因为标签在 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
,范围外变量的内存也可能被重用。
在任何情况下都不会泄漏局部变量。堆栈不会变得不平衡。问题中的代码没有任何危险。
在像 x86 这样使用 GCC 或 MSVC 的基于堆栈的处理器的情况下,所有局部变量的堆栈 space,无论范围如何,都将在函数 foo
的入口处保留。堆栈框架将在退出时展开,并按预期回收堆栈 space,而不管如何到达出口。
然而,对于 C++,情况有所不同。不完全是您的示例,但是如果您跳过构造函数,则构造函数将没有 运行 但是编译器仍将 运行 析构函数,这会导致混乱。幸运的是,正如 Joshua 在评论中指出的那样,现代编译器会检测到这种情况,并会生成编译时错误来避免这种情况。