为什么 C 编译器不捕获此错误?
Why don't C compilers catch this error?
在为 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
.
关于"in MSVC the process exits with a non-zero exit code.",MSVC编译器只符合C89标准,掉落main
结尾没有返回值,returns垃圾。如果需要支持这样的古老编译器,您应该在 main
末尾添加 return 0;
。
在为 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
.
关于"in MSVC the process exits with a non-zero exit code.",MSVC编译器只符合C89标准,掉落main
结尾没有返回值,returns垃圾。如果需要支持这样的古老编译器,您应该在 main
末尾添加 return 0;
。