Betrachten Sie die folgende switch
Aussage:
switch( value )
{
case 1:
return 1;
default:
value++;
// fall-through
case 2:
return value * 2;
}
Dieser Code wird kompiliert, aber ist er für C90 / C99 gültig (= definiertes Verhalten)? Ich habe noch nie Code gesehen, bei dem der Standardfall nicht der letzte ist.
EDIT:
Wie Jon Cage und KillianDS schreiben: Das ist wirklich hässlicher und verwirrender Code und ich bin mir dessen sehr bewusst. Ich interessiere mich nur für die allgemeine Syntax (ist sie definiert?) Und die erwartete Ausgabe.
c
switch-statement
Tanascius
quelle
quelle
goto
ist nicht böse. Frachtkult Anhänger sind! Sie können sich nicht vorstellen, welche Extreme Menschen vermeiden können,goto
weil es angeblich so böse ist und ihren Code wirklich unleserlich macht.goto
simuliere hauptsächlich so etwas wie einefinally
Klausel in Funktionen, in denen Ressourcen (Dateien, Speicher) beim Stoppen freigegeben werden müssen, und wiederhole für jeden Fehlerfall eine Liste vonfree
undclose
hilft nicht bei der Lesbarkeit. Es gibt zwar eine Verwendunggoto
, die ich vermeiden möchte, aber nicht kann, wenn ich aus einer Schleife ausbrechen möchte und mich in einerswitch
in dieser Schleife befinde.Antworten:
Der C99-Standard ist diesbezüglich nicht explizit, aber wenn man alle Fakten zusammenfasst, ist er vollkommen gültig.
A
case
unddefault
Label entsprechen einemgoto
Label. Siehe 6.8.1 Beschriftete Anweisungen. Besonders interessant ist 6.8.1.4, das das bereits erwähnte Duff's Device ermöglicht:Bearbeiten : Der Code innerhalb eines Schalters ist nichts Besonderes; Es ist ein normaler Codeblock wie in einer
if
Anweisung mit zusätzlichen Sprungbezeichnungen. Dies erklärt das Durchfallverhalten und warumbreak
es notwendig ist.6.8.4.2.7 gibt sogar ein Beispiel:
Die case-Konstanten müssen innerhalb einer switch-Anweisung eindeutig sein:
Alle Fälle werden ausgewertet und springen dann zur Standardbezeichnung, falls angegeben:
quelle
default
Fall habe, der andere Fälle um etwa 100: 1 dominiert, und ich weiß nicht, ob er gültig oder undefiniert ist, umdefault
den ersten Fall zu machen .Die case-Anweisungen und die default-Anweisung können in beliebiger Reihenfolge in der switch-Anweisung vorkommen. Die Standardklausel ist eine optionale Klausel, die übereinstimmt, wenn keine der Konstanten in den case-Anweisungen übereinstimmen kann.
Gutes Beispiel :-
Sehr nützlich, wenn Sie möchten, dass Ihre Fälle im Code in einer logischen Reihenfolge dargestellt werden (wie in Fall 1, Fall 3, Fall 2 / Standard) und Ihre Fälle sehr lang sind, sodass Sie nicht den gesamten Fall wiederholen möchten Code unten für die Standardeinstellung
quelle
Es ist gültig und in einigen Fällen sehr nützlich.
Betrachten Sie den folgenden Code:
Der Punkt ist, dass der obige Code lesbarer und effizienter als kaskadiert ist
if
. Sie könntendefault
am Ende setzen, aber es ist sinnlos, da es Ihre Aufmerksamkeit auf Fehlerfälle anstatt auf normale Fälle lenkt (was hier derdefault
Fall ist).Eigentlich ist es kein so gutes Beispiel,
poll
wenn Sie wissen, wie viele Ereignisse höchstens auftreten können. Mein eigentlicher Punkt ist , dass es sind Fälle mit einem definierten Satz von Eingabewerten , wo es ‚Ausnahmen‘ und normale Fälle. Ob es besser ist, Ausnahmen oder Normalfälle in den Vordergrund zu stellen, ist eine Frage der Wahl.Im Softwarebereich denke ich an einen anderen sehr üblichen Fall: Rekursionen mit einigen Endwerten. Wenn Sie es mit einem Schalter ausdrücken können,
default
wird der übliche Wert, der rekursiven Aufruf und unterscheidbare Elemente (Einzelfälle) enthält, die Terminalwerte sein. Es ist normalerweise nicht erforderlich, sich auf Endwerte zu konzentrieren.Ein weiterer Grund ist, dass die Reihenfolge der Fälle das Verhalten des kompilierten Codes ändern kann und dies für die Leistung von Bedeutung ist. Die meisten Compiler generieren kompilierten Assemblycode in derselben Reihenfolge, in der der Code im Switch angezeigt wird. Das unterscheidet den ersten Fall sehr von den anderen: Alle Fälle außer dem ersten beinhalten einen Sprung und leeren Prozessor-Pipelines. Möglicherweise verstehen Sie es wie einen Verzweigungsprädiktor, der standardmäßig den ersten angezeigten Fall im Switch ausführt. Wenn ein Fall viel häufiger ist als die anderen, dann haben Sie sehr gute Gründe, ihn als ersten Fall zu bezeichnen.
Das Lesen von Kommentaren ist der spezifische Grund, warum das Originalplakat diese Frage gestellt hat, nachdem die Reorganisation des Intel Compilers Branch Loop zur Codeoptimierung gelesen wurde .
Dann wird es zu einer Schlichtung zwischen Codelesbarkeit und Codeleistung kommen. Wahrscheinlich ist es besser, einen Kommentar abzugeben, um dem zukünftigen Leser zu erklären, warum ein Fall zuerst auftritt.
quelle
case
. Was bedrückend ist, ist, dass es genauso aussieht wie syntaxischer Zucker und keinen vorhandenen Code beschädigt, wenn es unterstützt wird.Ja, das ist gültig und unter Umständen sogar nützlich. Wenn Sie es nicht brauchen, tun Sie es im Allgemeinen nicht.
quelle
In einer switch-Anweisung ist keine Reihenfolge definiert. Sie können die Fälle als so etwas wie ein benanntes Etikett betrachten, wie ein
goto
Etikett. Im Gegensatz zu dem, was die Leute hier zu denken scheinen, wird im Fall von Wert 2 nicht auf die Standardbezeichnung gesprungen. Um dies mit einem klassischen Beispiel zu veranschaulichen, hier Duffs Gerät , das das Aushängeschild der Extreme vonswitch/case
in C.quelle
Ein Szenario, in dem ich es für angemessen halte, einen 'Standard' an einem anderen Ort als dem Ende einer case-Anweisung zu haben, befindet sich in einer Zustandsmaschine, in der ein ungültiger Zustand die Maschine zurücksetzen und so vorgehen sollte, als wäre es der Anfangszustand. Beispielsweise:
eine alternative Anordnung, wenn ein ungültiger Zustand die Maschine nicht zurücksetzen sollte, aber leicht als ungültiger Zustand erkennbar sein sollte:
Code an anderer Stelle kann dann nach (widget_state == WIDGET_INVALID_STATE) suchen und das für die Fehlerberichterstattung oder das Zurücksetzen des Status geeignete Verhalten bereitstellen. Beispielsweise könnte der Status-Barcode ein Fehlersymbol anzeigen, und die Menüoption "Widget starten", die in den meisten nicht inaktiven Zuständen deaktiviert ist, könnte sowohl für WIDGET_INVALID_STATE als auch für WIDGET_IDLE aktiviert werden.
quelle
Ein anderes Beispiel: Dies kann nützlich sein, wenn "Standard" ein unerwarteter Fall ist und Sie den Fehler protokollieren möchten, aber auch etwas Sinnvolles tun möchten. Beispiel aus einem meiner eigenen Codes:
quelle
Es gibt Fälle, in denen Sie ENUM in eine Zeichenfolge oder Zeichenfolge in enum konvertieren, wenn Sie in eine Datei schreiben / lesen.
Manchmal müssen Sie einen der Werte als Standard festlegen, um Fehler abzudecken, die beim manuellen Bearbeiten von Dateien auftreten.
quelle
Die
default
Bedingung kann überall innerhalb des Schalters sein, dass eine case-Klausel existieren kann. Es muss nicht die letzte Klausel sein. Ich habe Code gesehen, der den Standard als erste Klausel setzt. Dascase 2:
wird normal ausgeführt, obwohl die Standardklausel darüber steht.Als Test habe ich den Beispielcode in eine Funktion eingefügt, aufgerufen
test(int value){}
und ausgeführt:Die Ausgabe ist:
quelle
Es ist gültig, aber ziemlich böse. Ich würde vorschlagen, dass es im Allgemeinen schlecht ist, Durchbrüche zuzulassen, da dies zu einem sehr unordentlichen Spaghetti-Code führen kann.
Es ist mit ziemlicher Sicherheit besser, diese Fälle in mehrere switch-Anweisungen oder kleinere Funktionen aufzuteilen.
[Bearbeiten] @Tristopia: Ihr Beispiel:
wäre klarer in Bezug auf seine Absicht (glaube ich), wenn es so geschrieben wäre:
[edit2] @Tristopia: Ihr zweites Beispiel ist wahrscheinlich das sauberste Beispiel für eine gute Verwendung für die Nachverfolgung:
..aber persönlich würde ich die Kommentarerkennung in eine eigene Funktion aufteilen:
quelle
r
ist das Zielarray ,wc
der Eingangsschalterwchar_t
(utf8_length) {/ * Hinweis: Code fällt durch Fälle! * / Fall 3: r [2] = 0x80 | (wc & 0x3f); wc >> = 6; wc | = 0x800; Fall 2: r [1] = 0x80 | (wc & 0x3f); wc >> = 6; wc | = 0xc0; Fall 1: r [0] = wc; }for(i=0; s[i]; i++) { switch(s[i]) { case '"': case '\'': case '\\': d[dlen++] = '\\'; /* fall through */ default: d[dlen++] = s[i]; } }