c - 为什么 C 编译器不捕获此错误?

标签 c gcc clang goto segmentation-fault

在为 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


关于“在 MSVC 中,进程以非零退出代码退出。” , MSVC 编译器只符合 C89 标准,在 main 的结尾没有返回值,返回垃圾。如果需要支持这样的古老编译器,您应该在 main 的末尾添加 return 0;

关于c - 为什么 C 编译器不捕获此错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43860476/

相关文章:

c++ - 使用 readability-identifier-naming 时,clang-tidy 将 namespace 视为全局变量

c++ - shuffle() 函数和 SIMD 代码生成

c++ - GCC 声明友元函数重载,调用不明确,clang 编译

c - 函数指针是否强制清除指令流水线?

c++ - 在 GCC/C++ 下访问 Windows 注册表

c++ - 英语和希腊语 UTF 字符差异

c++ - GCC:__attribute__ ((format (printf, x, y)) 在使用可变参数宏调用函数时似乎不起作用

c - bsd gcc 预处理器宏 ##x## 没有提供有效的预处理标记

c - 默认 GCcflags

iphone - 获取被触摸的按钮的标题