Utilizzo di continue in un'istruzione switch


91

Voglio passare dal centro di switchun'istruzione all'istruzione loop nel codice seguente:

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        break;
    default:
        // get another something and try again
        continue;
    }
    // do something for a handled something
    do_something();
}

È questo un modo valido per utilizzare continue? Le continuedichiarazioni vengono ignorate dalle switchdichiarazioni? C e C ++ differiscono nel loro comportamento qui?


La tua idea va bene ma il ciclo sopra non verrà mai eseguito do_something().
antik

5
Anche se il controllo raggiunge il caso A o il caso B?
Alexander Poluektov,

18
Stavo per dire, antik su questo si sbaglia. Nel caso di A o B, verrà eseguito do_something (). Con l'impostazione predefinita verrà rilasciato.
Antony Woods,

3
@acron, questo è il comportamento previsto
Matt Joiner

1
Penso che questo sembri molto più sospetto e confuso e quindi più dannoso di un file goto.
phoeagon

Risposte:


57

Va bene, l' continueistruzione si riferisce al ciclo che lo racchiude e il tuo codice dovrebbe essere equivalente a (evitare tali istruzioni di salto):

while (something = get_something()) {
    if (something == A || something == B)
        do_something();
}

Ma se ti aspetti breakdi uscire dal ciclo, come suggerisce il tuo commento (riprova sempre con qualcos'altro, fino a quando non diventa falso), avrai bisogno di una struttura diversa.

Per esempio:

do {
    something = get_something();
} while (!(something == A || something == B));
do_something();

2
"equivalente" solo in senso semantico. il codice generato dal compilatore è molto diverso. con un'istruzione switch, il compilatore può generare una tabella di salto che evita confronti multipli e quindi è molto più veloce del confronto con ogni elemento 1 per 1.
chacham15

@ chacham15, perché il compilatore non ha potuto generare lo stesso codice per entrambi?
avakar

Le istruzioni switch @avakar generano tabelle di salto mentre l'altra rappresentazione è una serie di valutazioni logiche. google jump table per ulteriori informazioni.
chacham15

@ chacham15, cosa impedisce al compilatore di generare una tabella di salto per le due istruzioni if ​​o una serie di valutazioni logiche per lo switch?
avakar

1
Le istruzioni switch @avakar richiedono che i casi siano valori costanti, perché questo non è il caso delle istruzioni if, non può fare la stessa ottimizzazione (nota: sto parlando nel caso generale, è possibile dati determinati requisiti (ad es. solo valori const , solo alcuni operatori logici, ecc.) per eseguire l'ottimizzazione, ma è altamente dipendente dal compilatore e YMMV).
chacham15

21

Sì, va bene, è come usarlo in una ifdichiarazione. Ovviamente, non puoi usare a breakper uscire da un loop dall'interno di un interruttore.


Ma ifnon ha alcun effetto sul comportamento di continueo break. Come intendi che sia uguale?
Matt Joiner,

@ Matt voglio dire che continuerà il ciclo in entrambi i casi.

1
@ Neil, okay, la confusione è stata evitata.
Matt Joiner

1
@ KiJéy Non riesco a trovare alcun riferimento per questo, e in molti anni di programmazione in C non ho mai visto nessun compilatore che lo supporti ... Dove diavolo l'hai trovato?
arjunyg

2
Wow scusa, l'ho visto in PHP, pensavo fosse una vecchia pratica, si scopre che è solo PHP ...
Ki Jéy

15

Sì, continue verrà ignorato dall'istruzione switch e andrà alla condizione del ciclo da testare. Vorrei condividere questo estratto dal riferimento al linguaggio di programmazione C di Ritchie:

L' continueaffermazione è correlata a break, ma usata meno spesso; provoca la successiva iterazione del racchiude for, whileo dociclo per iniziare. In whilee do, questo significa che la parte di test viene eseguita immediatamente; in for, il controllo passa alla fase di incremento.

L'istruzione continue si applica solo ai cicli, non a switchun'istruzione. Un continueall'interno di un switchall'interno di un ciclo provoca l'iterazione del ciclo successivo.

Non ne sono sicuro per C ++.


8

È sintatticamente corretto e stilisticamente corretto.

Un buon stile richiede che ogni case:affermazione finisca con uno dei seguenti:

 break;
 continue;
 return (x);
 exit (x);
 throw (x);
 //fallthrough

Inoltre, case (x):subito dopo con

 case (y):
 default:

è consentito - raggruppare più custodie che hanno esattamente lo stesso effetto.

Tutto il resto è sospettato di essere un errore, proprio come if(a=4){...} naturalmente è necessario che racchiude loop ( while, for, do...while) per continueil lavoro. Non tornerà da case()solo. Ma un costrutto come:

while(record = getNewRecord())
{
    switch(record.type)
    {
        case RECORD_TYPE_...;
            ...
        break;
        default: //unknown type
            continue; //skip processing this record altogether.
    }
    //...more processing...
}

...va bene.


2
scusate per il necroposting, ma aggiungerei che una chiamata a exitsarebbe di solito anche una buona cosa per terminare un caso di switch.
Vality

1
Bene, ho tutto il dottor Frankenstein qui e faccio notare anche che default:non deve essere l'ultima / ultima voce - come sottolinea questa domanda ...
SlySven

1
@SlySven: Lexically, non è così, ma se non hai una buona ragione per non farlo durare, fallo durare. È spesso fonte di confusione se usato in altri luoghi.
SF.

1
@SF. beh, posso facilmente immaginare i casi in cui avrebbe più senso rendere il default:caso il primo anziché l'ultimo. Come "fai questo, a meno che tu non ottenga i seguenti valori insoliti, che dovrebbero essere gestiti come segue".
Ruslan

5

Sebbene tecnicamente validi, tutti questi salti oscurano il flusso di controllo, specialmente l' continueaffermazione.

Userei un trucco del genere come ultima risorsa, non come prima.

Che ne dite di

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        do_something();
    }        
}

È più breve ed esegue le sue cose in modo più chiaro.


1
scusa per la confusione Alexander, il codice è solo dimostrativo, ho una buona ragione (credo) per la struttura effettiva nel mio codice.
Matt Joiner

2
@ Matt: Ciò probabilmente significherebbe una struttura ancora più offuscata ... :)
visitatore

-2

Questo potrebbe essere un megabit in ritardo, ma puoi usare continue 2.

Alcune build / configurazioni php restituiranno questo avviso:

Avviso PHP: l'interruttore di targeting "continue" equivale a "interruzione". Volevi usare "continue 2"?

Per esempio:

$i = 1;

while ($i <= 10) {
    $mod = $i % 4;
    echo "\r\n out $i";
    $i++;
    switch($mod)
    {
        case 0:
            break;
        case 2:
            continue;
            break;
        default:
            continue 2;
            break;
    }
    echo " is even";
}

Questo produrrà:

out 1
out 2 is even
out 3
out 4 is even
out 5
out 6 is even
out 7
out 8 is even
out 9
out 10 is even

Testato con PHP 5.5 e versioni successive.


3
Questa NON è una domanda PHP.
Geoffrey

-4

Switch non è considerato come loop, quindi non puoi usare Continue all'interno di un'istruzione case in switch ...


3
L' switchistruzione è all'interno di un whileciclo, quindi continueè perfettamente valida.
Rick
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.