2015-07-22 29 views
23

stavo giocando con una certa sintassi e trovato alcune regole compilatore strane, si chiedeva che cosa il ragionamento è per questoC vs C++ switch definizione della variabile vs dichiarazione

C non verrà compilato questo, ma C++ sarà:

switch (argc) { 
case 0: 
    int foo; 
    break; 
default: 
    break; 
} 

Sia C e C++ si compilare questo:

switch (argc) { 
case 0: 
    ; int foo; 
    break; 
default: 
    break; 
} 

C verrà compilato questo, ma non C++:

switch (argc) { 
case 0: 
    ; int foo = 0; 
    break; 
default: 
    break; 
} 

gcc -v è gcc version 4.9.3 (MacPorts gcc49 4.9.3_0) se è importante. Mi rendo conto che la soluzione è quella di avvolgere il contenuto di case 0: con parentesi graffe, ma io sono più interessato al ragionamento per errori di compilazione

+5

[Questa risposta] (http://stackoverflow.com/a/92730/962089) è piuttosto pertinente. – chris

+2

Sembra che il secondo caso funzioni ancora per C++ se si imposta 'foo' in un'istruzione aggiuntiva. gcc si lamenta solo della variabile non utilizzata in [questo esempio] (http://coliru.stacked-crooked.com/a/ba80bc1da97d8212), e clang va bene con esso. – jaggedSpire

+1

@chris, Grazie, il terzo caso ha senso ora (non posso saltare l'inizializzazione in C++) – asimes

risposta

23
case 0: 
    int foo; 

sia in C e C++ una dichiarazione con etichetta è un'etichetta seguita da un comunicato. Tuttavia in C++ la definizione di un'istruzione include "dichiarazioni di blocco" (ovvero dichiarazioni e definizioni che possono apparire in un blocco) mentre in C non esiste (in C un blocco è una sequenza di "elementi di blocco", che sono entrambi blocchi dichiarazioni o dichiarazioni - in C++ è una sequenza di dichiarazioni, che includono dichiarazioni di blocco).

case 0: 
    ; int foo; 

Questo funziona perché ; è una dichiarazione (n vuoto) sia in C e C++, ecco che effettivamente abbiamo un'etichetta seguita da un'istruzione.

case 0: 
    ; int foo = 0; 

Come già spiegato nei commenti, questo non funziona in C++ perché C++ rende illegale per saltare sopra un'inizializzazione.

+0

Questa è una bella risposta, ma il terzo caso è ancora quello che più mi confonde. Come sta saltando un'inizializzazione? Perché posizionare la definizione all'interno delle parentesi graffe evita di saltare un'inizializzazione? – asimes

+1

@asimes, quando si inseriscono le parentesi, '{; int foo = 0;} 'è l'istruzione per l'istruzione * etichettata *. Quando non lo fai, 'int foo = 0;' fa parte dello switch piuttosto che un'istruzione per un caso, quindi si trova nell'ambito oltre l'etichetta successiva, ma la sua inizializzazione viene saltata. – chris

+0

@asimes È possibile saltare l'inizializzazione perché potrebbe passare al caso predefinito, dove 'foo' sarebbe in ambito, ma non inizializzato. Se aggiungi delle parentesi, 'pippo' non è più incluso nel blocco predefinito.Fondamentalmente, le regole del "saltare sopra un'inizializzazione" vieta di saltare "al centro" nell'ambito di una variabile che ha un inizializzatore. Cioè, ti è permesso di saltare all'inizializzazione o dopo che la variabile è uscita dal campo di applicazione, ma non in qualsiasi punto tra questi punti. – sepp2k