Verwenden Sie continue in einer switch-Anweisung

88

Ich möchte von der Mitte einer switchAnweisung zur Schleifenanweisung im folgenden Code springen :

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();
}

Ist dies eine gültige Verwendung continue? Werden continueAnweisungen von switchAnweisungen ignoriert ? Unterscheiden sich C und C ++ in ihrem Verhalten hier?

Matt Joiner
quelle
Ihre Idee ist in Ordnung, aber die obige Schleife wird niemals ausgeführt do_something().
Antik
5
Auch wenn die Kontrolle Fall A oder Fall B erreicht?
Alexander Poluektov
18
Ich wollte sagen, Antik ist falsch. Im Fall von A oder B wird do_something () ausgeführt. Mit Standard wird es Kaution.
Antony Woods
3
@acron, das ist das beabsichtigte Verhalten
Matt Joiner
1
Ich denke, das sieht viel verdächtiger und verwirrender aus und ist daher schädlicher als ein goto.
Phoeagon

Antworten:

56

Es ist in Ordnung, die continueAnweisung bezieht sich auf die einschließende Schleife, und Ihr Code sollte äquivalent sein (um solche Sprunganweisungen zu vermeiden):

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

Wenn Sie jedoch erwarten break, die Schleife zu verlassen, wie in Ihrem Kommentar vorgeschlagen (es wird immer wieder mit einem anderen Element versucht, bis es als falsch ausgewertet wird), benötigen Sie eine andere Struktur.

Zum Beispiel:

do {
    something = get_something();
} while (!(something == A || something == B));
do_something();
Besucher
quelle
2
"äquivalent" nur im semantischen Sinne. Der vom Compiler generierte Code ist sehr unterschiedlich. Mit einer switch-Anweisung kann der Compiler eine Sprungtabelle generieren, die mehrere Vergleiche vermeidet und somit viel schneller ist als der Vergleich mit jedem Element 1 um 1.
chacham15
@ chacham15, warum konnte der Compiler nicht für beide den gleichen Code generieren?
Avakar
@avakar switch-Anweisungen generieren Sprungtabellen, während die andere Darstellung eine Reihe logischer Auswertungen ist. Google Jump Table für weitere Informationen.
Chacham15
@ chacham15, was hindert den Compiler daran, eine Sprungtabelle für die beiden if-Anweisungen oder eine Reihe logischer Auswertungen für den Switch zu generieren?
Avakar
1
@avakar switch-Anweisungen erfordern, dass die Fälle konstante Werte sind, da dies bei if-Anweisungen nicht der Fall ist und nicht dieselbe Optimierung vorgenommen werden kann (Hinweis: Ich spreche im allgemeinen Fall, es ist unter bestimmten Anforderungen möglich (z. B. nur const-Werte) , nur bestimmte logische Operatoren usw.), um die Optimierung vorzunehmen, aber es ist stark compilerabhängig und YMMV).
Chacham15
20

Ja, es ist in Ordnung - es ist wie in einer ifAnweisung. Natürlich können Sie a nicht verwenden break, um aus einer Schleife innerhalb eines Schalters auszubrechen.


quelle
Hat ifaber keinen Einfluss auf das Verhalten von continueoder break. Wie meinst du es ist gleich?
Matt Joiner
@Matt Ich meine, es wird die Schleife in beiden Fällen fortsetzen.
1
@Neil, okay, Verwirrung abgewendet.
Matt Joiner
1
@ KiJéy Ich kann keine Referenz dafür finden, und in vielen Jahren der C-Programmierung habe ich noch nie einen Compiler gesehen, der dies unterstützt ... Wo um alles in der Welt haben Sie das gefunden?
Arjunyg
2
Wow sorry, ich habe das in PHP gesehen, dachte, es sei eine alte Praxis, es stellt sich heraus, dass es nur PHP ist ...
Ki Jéy
15

Ja, continue wird von der switch-Anweisung ignoriert und wechselt zum Zustand der zu testenden Schleife. Ich möchte diesen Auszug aus der Referenz zur Programmiersprache C von Ritchie teilen:

Die continueAussage bezieht sich auf break, wird aber seltener verwendet; es bewirkt , dass die nächste Iteration der umschließenden for, whileoder doSchleife zu beginnen. Im whileund dobedeutet dies, dass der Testteil sofort ausgeführt wird; In der forgeht die Steuerung zum Inkrementierungsschritt über.

Die continue-Anweisung gilt nur für Schleifen, nicht für eine switchAnweisung. Ein continueinnerhalb einer switchinnerhalb einer Schleife bewirkt die nächste Schleifeniteration.

Da bin ich mir für C ++ nicht sicher.

Islam Elshahat
quelle
8

Es ist syntaktisch korrekt und stilistisch in Ordnung.

Für einen guten Stil muss jede case:Aussage mit einer der folgenden Aussagen enden:

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

Zusätzlich case (x):sofort mit

 case (y):
 default:

ist zulässig - Bündelung mehrerer Fälle, die genau den gleichen Effekt haben.

Alles andere steht im Verdacht , einen Fehler zu sein, genau wie if(a=4){...} Natürlich brauchen Sie umschließenden Schleife ( while, for, do...while) für continuean die Arbeit. Es wird nicht zu case()alleine zurückkehren. Aber ein Konstrukt wie:

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

...es ist okay.

SF.
quelle
2
Entschuldigung für die Nekropostierung, aber ich würde hinzufügen, dass ein Anruf bei exitnormalerweise auch eine gute Sache ist, um einen Switch-Fall zu beenden.
Vality
1
Nun, ich werde alle Dr. Frankenstein hier haben und auch darauf hinweisen, dass default:dies nicht der letzte / unterste Eintrag sein muss - wie diese Frage zeigt ...
SlySven
1
@SlySven: Lexikalisch nicht, aber wenn Sie keinen guten Grund haben, es nicht zuletzt zu machen, machen Sie es zuletzt. Es ist oft verwirrend, wenn es an anderen Orten verwendet wird.
SF.
1
@ SF. Nun, ich kann mir leicht die Fälle vorstellen, in denen es sinnvoller wäre, default:den ersten als den letzten Fall zu machen . Zum Beispiel "Tun Sie dies, es sei denn, Sie erhalten die folgenden ungewöhnlichen Werte, die wie folgt behandelt werden sollten".
Ruslan
5

Alle diese Sprünge sind zwar technisch gültig, verdecken jedoch den Kontrollfluss - insbesondere die continueAussage.

Ich würde einen solchen Trick als letzten Ausweg verwenden, nicht als ersten.

Wie wäre es mit

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

Es ist kürzer und führt seine Sachen klarer aus.

Alexander Poluektov
quelle
1
Entschuldigung für die Verwirrung Alexander, der Code dient nur zu Demonstrationszwecken. Ich habe guten Grund (glaube ich) für die tatsächliche Struktur in meinem Code.
Matt Joiner
2
@ Matt: Das würde wahrscheinlich eine noch verschleiertere Struktur bedeuten ... :)
Besucher
-2

Dies könnte ein Megabit zu spät sein, aber Sie können verwenden continue 2.

Einige PHP Builds / Configs geben diese Warnung aus:

PHP-Warnung: Der Zielschalter "Weiter" entspricht "Pause". Wollten Sie "continue 2" verwenden?

Zum Beispiel:

$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";
}

Dies wird Folgendes ausgeben:

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

Getestet mit PHP 5.5 und höher.

Adrian S.
quelle
3
Dies ist KEINE PHP-Frage.
Geoffrey
-4

Switch wird nicht als Schleife betrachtet, daher können Sie Continue nicht in einer case-Anweisung in switch verwenden ...

Jitendra Nagar
quelle
3
Die switchAnweisung befindet sich in einer whileSchleife und continueist daher absolut gültig.
Rick