2013-06-19 57 views
14

回顧我碰到的東西來了,如同一些第三方的C代碼:開關箱怪異的作用域

switch (state) { 
case 0: 
    if (c=='A') { // open brace 
     // code... 
    break; // brace not closed! 
case 1: 
    // code... 
    break; 
    } // close brace! 
case 2: 
    // code... 
    break; 
} 

其中在代碼中,我正在審查似乎只是一個錯字,但我很驚訝,這與出錯誤編譯。

爲什麼這個有效的C?
與在預期位置關閉大括號相比,此代碼的執行效果如何?
有沒有這種情況可以使用?

編輯:在這個例子中我看着都斷裂存在(如上) - 但答案可能還包括行爲,如果突破的情況下,0或1

+0

那麼,那是因爲'switch-case'的奇怪'goto label'實現。雖然你的具體情況可能有點奇怪,很難想出一個用例(查看[* Duff's Device *](http://en.wikipedia.org/wiki/Duff%27s_device)),但突破性案例的一般概念(當你離開'break'時)確實非常有用。 –

+2

如果您現在正在尋求關於* Duff設備*工作原理的解釋,請點擊此處(http://stackoverflow.com/questions/514118/how-does-duffs-device-work)。 – devnull

+0

在這種情況下,'case 1:'被編譯器視爲一個單獨的標籤。語法完全有效,但在這種情況下幾乎可以肯定(從上下文來看)邏輯錯誤。通過發送'state == 1'來測試它,你會看到不正確的結果。 – Chad

回答

12

沒有它不僅是有效的,類似的結構已經在真正的代碼,例如,Duff's Device,這是複製一個緩衝展開循環使用:

send(to, from, count) 
register short *to, *from; 
register count; 
{ 
     register n = (count + 7)/8; 
     switch(count % 8) { 
     case 0: do { *to = *from++; 
     case 7:   *to = *from++; 
     case 6:   *to = *from++; 
     case 5:   *to = *from++; 
     case 4:   *to = *from++; 
     case 3:   *to = *from++; 
     case 2:   *to = *from++; 
     case 1:   *to = *from++; 
       } while(--n > 0); 
     } 
} 

由於switch聲明真的只計算一個地址並跳轉到它,它很容易看到爲什麼它可以與其他重疊控制結構;其他控制結構中的行也具有可以跳轉目標的地址!

在你提交的案例中,想象一下如果代碼中沒有switchbreak s。當您完成if聲明的then部分的執行時,您只需繼續操作,以便進入case 2:。現在,由於您有switchbreak,因此break可能會突破。按照MSDN page, 「The C break statement」

休息語句終止最近的封閉做,的執行,開關,或在其出現聲明。控制權傳遞給終止語句後面的語句。

由於最近的封閉開關,或語句是你開關(注意:如果沒有包括在該列表中),然後如果你」重新在then區塊內,您轉移到switch聲明的外部。但是,有趣的是,如果輸入case 0會發生什麼情況,但c == 'A'是錯誤的。然後if將控制權轉移到then塊的大括號之後,然後開始執行case 2中的代碼。

+1

c!='A'的情況下,你解釋它的方式是有道理的 - 但是從代碼快速瀏覽直觀的FAR! – Ricibob

+0

@Ricibob我承認,它確實需要一定量的視圖C作爲「高級裝配」。如果你已經花了一些時間看C代碼是如何編譯成彙編/機器代碼的,它會變得更容易一些。例如,在'if condition then'語句中,只有一個跳轉;如果條件是_false_,則跳轉到「then」部分之後。如果你在'then'部分結束,那麼繼續執行也會讓你在那裏。不需要「休息」。然而,在迭代形式中,例如'while condition block',塊被編譯爲有跳回到開始測試... –

+0

@Ricibob ...條件再次,或者再次進入塊,或者跳到該塊。所以迭代構造需要'break',因爲身體會將它們帶回到開頭。 'switch'雖然有點奇怪,因爲它不會迭代。它只是需要'bre​​ak',因爲程序員想要執行一個case而不是其他的,而且沒有中斷,他們必須在switch語句後面寫一個新標籤,並且從每個case轉到goto。 。在任何情況下,做這種控制流交錯可能不是一種好的風格,除非你... –

3

在C和C++中,只要不跳過任何變量聲明,跳轉到循環和塊都是合法的。您可以使用goto作爲示例來檢查this answer,但我不明白爲什麼相同的想法不適用於switch塊。

語義與}高於case 1的語義不同。
此代碼實際上表示,如果state == 0c != 'A'則轉到case 2,因爲這是if語句的大括號。然後它會處理該代碼,並在case 2代碼的末尾點擊break聲明。

+0

+1提及跳過變量聲明 – legends2k