2013-01-11 23 views
17

Supponiamo questi codice compilato in g++:L'istruzione goto non può attraversare la definizione della variabile?

#include <stdlib.h> 

int main() { 
    int a =0; 

    goto exit; 

    int *b = NULL; 

exit: 
    return 0; 
} 

g++ getteranno errori:

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’ 

Sembra che la goto non può croce definizione puntatore, ma gcc compila loro ok, niente lamentato.

Dopo aver corretto l'errore, è necessario dichiarare tutti i puntatori prima di qualsiasi delle istruzioni goto, vale a dire che è necessario dichiarare questi puntatori anche se non sono necessari al momento (e violazione con alcuni principi).

Quale motivo per cui il disegno di origine considera che g++ è vietato l'utile istruzione tail-goto?


Aggiornamento:

goto può attraversare variabile (qualsiasi tipo di variabili, non limitato a puntatore) dichiarazione, ma ad eccezione di quelli che ha ottenuto un valore di inizializzazione. Se togliamo l'incarico NULL in precedenza, g++ taci. Quindi, se si desidera dichiarare variabili che tra goto -cross-area, non sono inizializzarle (e comunque violare alcuni principi).

risposta

24

Goto non può ignorare le definizioni di variabili, perché quelle variabili non sarebbero esistenti dopo il salto, poiché la durata della variabile inizia nel punto di definizione. La specifica non sembra menzionare esplicitamente goto, non deve farlo, ma è implicita in ciò che si dice sulla durata variabile.

Poiché l'errore menziona [-fpermissive], è possibile trasformarlo in avviso specificando il flag del compilatore. Questo indica due cose. Che una volta era permesso (la variabile esisterebbe, ma non sarebbe stato inizializzato dopo il salto) e che gli sviluppatori di gcc ritengono che la formulazione della specifica implichi che ciò sia proibito (o implica un comportamento indefinito che hanno scelto di vietare perché possono).

Il compilatore controlla solo se la variabile esiste formalmente, non se è utilizzata, altrimenti i risultati sarebbero piuttosto incoerenti. Ma se non avete bisogno di più la variabile, si può finire che è la vita da soli, rendendo il "tail-goto" vitali:

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

è perfettamente valida.

Su un lato, si sta compilando con g++, ma finché il file ha estensione .c, è considerato C e non C++. gcc e g++ differiscono in alcuni flag di default, principalmente per la fase linker, ma entrambi compilano qualsiasi linguaggio installato (C, C++, ObjC, ObjC++) come determinato dall'estensione.

2

C'è un work-around facile per quei tipi primitivi come int:

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

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