为什么 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

允许跳过局部变量的初始化,效果是变量未初始化。

将未初始化的变量传递给 putsundefined 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;