2017-05-09 106 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;

相關問題