2017-05-09 99 views
1

虽然为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

+0

这是未定义的行为。您跳过了一个变量声明,并尝试稍后使用它。即使*尝试*做到这一点,它有什么意义?你期待什么样的结果? – InternetAussie

+2

这不是编译器的工作。 – kaylum

+2

@InternetAussie OP提到他是代码打高尔夫球。也许对[this](https://codegolf.stackexchange.com/q/23250/61563)有挑战? –

回答

4

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

将未初始化的变量传递给puts的方法是undefined behaviour,但不是违反约束或语法错误。这意味着C标准不要求编译器给出错误。

但是,编译器是周到的,并倾向于提供各种警告标志。在这种情况下,gcc可以警告潜在的未初始化变量的使用。通过使用-Wall-Wuninitialized,您应该看到警告。您可以使用-Werror-Werror=uninitialized来获取错误而不是警告。

有些人建议始终以标准模式编译并附有警告,例如-std=c11 -pedantic -Wall -Wextra


关于“在MSVC中,进程退出非零退出代码”。 ,MSVC编译器只能达到C89标准,其中main的末尾没有返回值,返回垃圾。如果需要支持那样的古代编译器,你应该在main的末尾有return 0;

相关问题