2012-03-16 12 views
26

Sto scrivendo un codice C e nel mio codice ho due cicli annidati. Su una condizione particolare voglio break dal ciclo interno e continue il ciclo esterno. Ho cercato di ottenere ciò utilizzando un'etichetta all'estremità del codice del ciclo esterno e, a condizione, l'etichetta goto. Comunque gcc dà un errore che non posso avere un'etichetta alla fine di un'istruzione composta. Perchè no?In C perché hai bisogno di una dichiarazione dopo un'etichetta goto?

Nota 1: Questa non è una dichiarazione switch e che domanda è stato risposto elsewhere.

Nota 2: Questa non è una domanda sullo stile e se dovrei o non dovrei usare le dichiarazioni goto o variabili condizionali.

EDIT: Le persone hanno chiesto un esempio e posso fare un esempio un po 'facile di verificare se un array è un sottoarray di un altro array

int superArray[SUPER_SIZE] = {...}, subArray[SUB_SIZE] = {...}; 
    int superIndex, subIndex; 

    for (superIndex=0; superIndex<SUPER_SIZE-SUB_SIZE; superIndex+=1) 
    { 
     for (subIndex=0; subIndex<SUB_SIZE; subIndex+=1) 
     if (superArray[superIndex+subIndex] != subArray[subIndex]) 
      goto break_then_continue; 

     // code that executes if subArray is a sub array 

     break_then_continue: 
    } 
+3

può fornire un piccolo programma che riproduce il messaggio di errore che si ottiene? – sarnold

+0

buona fortuna e attenzione ai velociraptor – wim

risposta

34

Nello standard è esplicitamente detto che le etichette appartengono a una dichiarazione, quindi, un semplice punto e virgola (;) dopo la vostra l'etichetta può aggirare il problema a cui stai correndo, dal momento che conta come una dichiarazione.

C'è anche un esempio di utilizzo di un "vuoto" dichiarazione 6.8.3/6.

ESEMPIO 3 Un'istruzione nullo può anche essere utilizzato per trasportare un'etichetta poco prima della chiusura} di un'istruzione composta

while (loop1) { 
    /* ... */ 

    while (loop2) { 
    /* ... */ 

    if (want_out) 
     goto end_loop1; 

    /* ... */ 
    } 

    /* ... */ 

    end_loop1: ; 
} 

Nello standard Questo è denominato a come null statement.


6.8.1 dichiarazioni con etichetta

Syntax 
    1 labeled-statement: 
     identifier : statement 
     case constant-expression : statement 
     default : statement 

noti che statement non è un optional nella citazione di cui sopra.


+0

+1 Ottima risposta. Adoro l'esempio preso direttamente dallo standard. – Caleb

+0

Grazie per l'ottima risposta. Stavo cercando * perché * 'gcc' funziona nel modo in cui non fa come aggirarlo. Comunque la tua risposta tende ad indicare che è semplicemente il modo in cui è scritto c. Questo è in gran parte un retaggio da quando la compilazione C era solo un'astrazione minore del codice assembly. – AntonDelprado

+0

@AntonDelprado In realtà è piuttosto semplice, goto posizionerà l'etichetta prima del comando/espressione e se non c'è nulla di simile, non c'è nessun posto dove saltare. Questa affermazione vuota è usata così è possibile. in questo modo si salta su un equivalente innocuo della funzione di assemblaggio NOP (nessuna operazione). – AoeAoe

3

è sufficiente scrivere:

label: ; 

Il punto e virgola è un'istruzione vuota. Ne hai bisogno perché la lingua è definita così; devi andare a una dichiarazione, anche se è vuota.

for (int i = 0; i < N; i++) 
    { 
     for (int j = 0; i < M; j++) 
     { 
      ... 
      if (some_condition) 
       goto continue_loop1; 
      ... 
     } 
continue_loop1: ; 
    } 

Si può discutere sull'indentazione sull'etichetta.

+0

Si noti inoltre che una dichiarazione, anche con un'inizializzazione, non è un'istruzione che può essere etichettata: 'label1: int x = function (y, z);' non è valido. –

3

L'etichetta deve indicare una dichiarazione.

mandati C questo:

(C99, 6.8.1 dichiarazioni con etichetta P4) " Qualsiasi dichiarazione può essere preceduto da un prefisso che dichiara un identificatore come nome di etichetta."

Nel tuo caso è possibile utilizzare una dichiarazione nullo:

void foo(void) 
{ 
    goto bla; 

    bla: 
    ; 
} 

dichiarazioni Null eseguire alcuna operazione.

Oppure si può anche utilizzare un'istruzione composto (un blocco) se si dispone di dichiarazioni:

void foo(void) 
{ 
    goto bla; 

    bla: 
    { 
     int x = 42; 
     printf("%d\n", x); 
    } 
} 
Problemi correlati