为什么C编译器不能捕获这个错误?
问题描述:
虽然为code golf比赛编写了一些代码,但我注意到了一些奇怪的行为。例如:为什么C编译器不能捕获这个错误?
int main(void)
{
goto jmp;
char *str = "Hello, World!";
jmp:
puts(str);
}
与海湾合作委员会(和锵和MSVC)导致没有警告或错误编译,但运行它抛出SIGSEGV
。编译器怎么会不知道goto
跳过变量声明?
我决定测试了这一点,并重写的例子(错误):
int main(void)
{
goto jmp;
int x;
jmp:
putchar(x);
}
再次,编译产生任何错误。此外,执行时不会引发任何操作,但在MSVC中,该进程以非零退出代码退出。
这是怎么回事?这是我们不应该使用goto
s的另一个原因吗?第二个例子中怎么没有发现错误,而第一个例子是SIGSEGV
?
答
它允许跳过局部变量的初始化,其效果是该变量未初始化。
将未初始化的变量传递给puts
的方法是undefined behaviour,但不是违反约束或语法错误。这意味着C标准不要求编译器给出错误。
但是,编译器是周到的,并倾向于提供各种警告标志。在这种情况下,gcc可以警告潜在的未初始化变量的使用。通过使用-Wall
或-Wuninitialized
,您应该看到警告。您可以使用-Werror
或-Werror=uninitialized
来获取错误而不是警告。
有些人建议始终以标准模式编译并附有警告,例如-std=c11 -pedantic -Wall -Wextra
。
关于“在MSVC中,进程退出非零退出代码”。 ,MSVC编译器只能达到C89标准,其中main
的末尾没有返回值,返回垃圾。如果需要支持那样的古代编译器,你应该在main
的末尾有return 0;
。
这是未定义的行为。您跳过了一个变量声明,并尝试稍后使用它。即使*尝试*做到这一点,它有什么意义?你期待什么样的结果? – InternetAussie
这不是编译器的工作。 – kaylum
@InternetAussie OP提到他是代码打高尔夫球。也许对[this](https://codegolf.stackexchange.com/q/23250/61563)有挑战? –