在为 code golf 编写代码时比赛中,我注意到一些奇怪的行为。例如:
int main(void)
{
goto jmp;
char *str = "Hello, World!";
jmp:
puts(str);
}
使用 GCC(以及 Clang 和 MSVC)编译不会产生任何警告或错误,但运行它会抛出 SIGSEGV
。为什么编译器没有发现 goto
正在跳过变量声明?
我决定测试这个(错误?)并重写示例:
int main(void)
{
goto jmp;
int x;
jmp:
putchar(x);
}
同样,编译没有产生任何错误。此外,执行时不会抛出任何内容,但在 MSVC 中,进程以非零退出代码退出。
这是怎么回事?这仅仅是我们不应该使用 goto
的另一个原因吗?为什么在第二个示例中没有抛出错误,而在第一个示例中抛出 SIGSEGV
?
最佳答案
允许跳过局部变量的初始化,结果是变量未初始化。
将未初始化的变量传递给puts
是undefined behaviour ,但不是约束冲突也不是语法错误。这意味着 C 标准不要求编译器给出错误。
但是,编译器是经过深思熟虑的,并倾向于提供各种警告标志。在这种情况下,gcc 可以警告可能使用未初始化的变量。通过使用 -Wall
或 -Wuninitialized
,您应该会看到一条警告。您可以使用 -Werror
或 -Werror=uninitialized
获取错误而不是警告。
有些人建议总是在带有警告的标准模式下编译,例如-std=c11 -pedantic -Wall -Wextra
。
关于“在 MSVC 中,进程以非零退出代码退出。” , MSVC 编译器只符合 C89 标准,在 main
的结尾没有返回值,返回垃圾。如果需要支持这样的古老编译器,您应该在 main
的末尾添加 return 0;
。
关于c - 为什么 C 编译器不捕获此错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43860476/