2013-01-11 26 views
17

假設這些代碼在編譯g++聲明goto不能跨越變量定義?

#include <stdlib.h> 

int main() { 
    int a =0; 

    goto exit; 

    int *b = NULL; 

exit: 
    return 0; 
} 

g++會引發錯誤:

goto_test.c:10:1: error: jump to label ‘exit’ [-fpermissive] 
goto_test.c:6:10: error: from here [-fpermissive] 
goto_test.c:8:10: error: crosses initialization of ‘int* b’ 

好像該goto不能交叉指針的定義,但gcc編譯他們好了,沒有什麼抱怨。

修正了錯誤之後,我們必須在任何goto語句之前聲明所有指針,也就是說即使您目前不需要它們(以及違反某些原則),也必須聲明這些指針。

g++禁止有用的原產地設計考慮tail-goto聲明?


更新:

goto可以穿過變量(變量,不限於指針的任何類型的)聲明,但除了那些有一個初始化值。如果我們刪除上面的NULL作業,g++現在保持沉默。所以如果你想聲明goto-交叉區域之間的變量,不要對它們進行初始化(並且仍然違反了一些原則)。

回答

24

Goto不能跳過變量的定義,因爲變量的生命週期從定義的角度開始,因此這些變量不會跳過。該規範似乎沒有明確提到goto不能這麼做,但它隱含在關於變量生命週期的內容中。

由於錯誤提到[-fpermissive],您可以通過指定該編譯器標誌將其變爲警告。這表明兩件事。它曾經被允許(變量會存在,但在跳轉後未被初始化),並且gcc開發人員認爲規範措辭暗示這是禁止的(或者意味着它是不確定的行爲,因爲它們可以選擇禁止它們)。

編譯器只檢查變量是否正式存在,而不是它是否被使用,否則結果會相當不一致。但是,如果你不需要的變量了,你可以結束它自己的生命週期,使得「尾轉到」可行的:

int main() { 
    int a =0; 
    goto exit; 
    { 
     int *b = NULL; 
    } 
exit: 
    return 0; 
} 

是完全有效的。

在附註中,您正在使用g++進行編譯,但只要文件的擴展名爲.c,它就被認爲是C而不是C++。 gccg++在某些默認標誌中有所不同,主要針對鏈接器階段,但它們都編譯由擴展確定的任何已安裝的語言(C,C++,ObjC,ObjC++)。

2

有一個簡單的工作環境對於那些原始的類型,如int

// --- original form, subject to cross initialization error. --- 
// int foo = 0; 

// --- work-around form: no more cross initialization error. --- 
int foo; foo = 0;