2011-07-22 21 views
17

這是我想知道的一些問題。鑑於下面的代碼,我們可以肯定它的輸出嗎?在變量定義之前轉到 - 它的值會發生什麼?

void f() { 
    int i = 0; 
    z: if(i == 1) goto x; else goto u; 
    int a; 
    x: if(a == 10) goto y; 
    u: a = 10; i = 1; goto z; 
    y: std::cout << "finished: " << a; 
} 

這是保證根據C++標準輸出finished: 10嗎?或者可以在編譯器佔據a被存入寄存器,當goto來之前a的地方嗎?

+0

你基本上是問goto語句是否是一個順序點? –

+0

@Armen如果'a'是類類型的,那麼在它調用它的析構函數之前跳轉。所以我想知道它是否是非班級類型,在它的價值失效之前會跳躍?因此,跳到'z',然後到'u',將'a'保持爲值'10',或者一個局部變量可能使用的某個隨機的其他值,或者'z'處的一些彙編程序操作? –

+0

C++ 0x標準規模較大但寫得較好。與此同時,我們正在糾結於合法性而不是處理現實。我越來越相信上面的代碼是不確定的,應該(即使合法)被編譯器拒絕。 – spraff

回答

0

它不能放棄一個變量定義。這應該是一個錯誤。

+0

它允許POD的 –

+0

它*編譯*,並且*完成*:打印'完成:10',至少使用G ++。即使有'牆 - 外掛'。問題在於標準對此有何評論。 – DevSolar

6

注:閱讀評論這一個第一。約翰尼斯或多或少地用一個很好的標準報價擊倒了我的整個論點。 ;-)


我沒有C++可用的標準,所以我必須從C標準來推斷。

令人驚訝的是(對我來說),章節6.2.1 標識符的範圍沒有說明從其聲明開始的標識符的範圍(正如我會猜到的)。 int a,在例如具有塊範圍,其中「在相關聯的塊的末端終止」,並認爲是所有所述關於它。章節6.8.6.1 goto語句表示「goto語句不應該從具有可變修改類型的標識符的範圍之外跳轉到該標識符的範圍之內」 - 但是由於您的goto只能在內跳轉塊(和,因此,int a範圍,即似乎是OK儘可能ISO/IEC 9899:1999關注

這個頗爲驚訝 ...

編輯#1:快速谷歌後,我掌握了C++ 0x最終草案。相關說法,我認爲,這是在這裏(6.7 聲明語句,突出礦井):

有可能轉移到塊,但不是在某種程度上 繞過與初始化聲明。 ,其從點與自動 存儲持續時間的變量不是在範圍上的點是在範圍上跳躍的程序是 形成不良除非該變量具有標量類型,類型與 一個平凡缺省構造和一個簡單的析構函數,一個CV-合格 版本這些類型之一的,或 前述類型之一的陣列,並且被聲明沒有初始化

我覺得你的代碼是由標準的標準確定。但是,屁股醜陋,請記住你。 ;-)

編輯#2:讀你的評論關於可能破壞int a由於向後跳躍,我發現這(6。6個跳轉語句,突出礦):

轉出一個循環,一個塊外,或回過去初始化的變量的 具有自動存儲持續時間涉及對象與 自動銷燬存儲期限在範圍內,但從 轉移的點不在轉移到的點上。

一,int a未被「初始化」,並且如果我正確理解標準術語,它不是一個對象。

+1

'int'雖然不是一個可變的修改類型。對於a *的*範圍,C草稿說:「每個枚舉常量的範圍只是在枚舉器列表中出現它的定義枚舉器之後開始的。任何其他標識符的範圍都是在其聲明完成後開始的。」所以我*從* a範圍之外跳到裏面。 –

+0

@Johannes Schaub:關於C的有趣之處在於:它不允許在語句之後使用變量定義,對嗎?或者在C99中使用它? –

5

6.7/3說

從一個點與 自動存儲持續時間的局部變量是在範圍上並不對點,它是在 範圍格式不正確,除非變量具有跳轉的程序POD類型(3.9)和 聲明沒有初始化(8.5)。

所以這應該沒問題。

然後,在6.6/2:

在退出範圍(但是完成),析構函數(12.4)是 稱爲用於與自動存儲持續時間 (3.7.2)的所有構造的對象(命名對象或臨時表格),按照其聲明的相反順序在該範圍內聲明。

現在,這意味着,我認爲a是烤麪包,當你跳回到z和你不能」做出的a無初始化聲明將如何表現它執行第二次任何保證。

見6.7/2:

變量與自動存儲持續時間(3.7.2)每個 一次執行其declarationstatement被初始化。與塊聲明的自動 存儲持續時間的變量被破壞從 塊(6.6)退出。

所以它看起來像我沒有一個保證,你會得到10,但似乎很難想象一個編譯器哪裏不會是這種情況。

+2

「這似乎很難想象編譯器哪裏不會是這種情況。」 - 如果這是合法的,我可以想像它。比較'i == 1'可以通過將'i'複製到寄存器,將'1'複製到寄存器並比較它們來工作。同時,優化器可能已經決定'a'應該存儲在寄存器中。最後,同一個寄存器可能被分配給'a'和'1',因爲當執行比較時'a'不在範圍內。 –

0

是否保證根據C++標準輸出finished: 10

我想是的,它必須!

爲什麼?因爲進行了聲明,直到它的範圍(函數的端)的端部,並通過定義a生命它只能使用一次,並從那裏在保持其值,直到破壞其爲在函數的結束初始化。

+0

事實上,標準說如果你在聲明一個變量之前回去,它會被破壞並且可以被重新初始化。 –

+0

@Mark B:我站好了! –

相關問題