Kann ich Code außerhalb von Fällen in einen Switch einfügen?

7

Angenommen:

%Vor%

Ist es "legal", das zusätzliche Bit Code auszuführen, das ich vor dem ersten case hinzugefügt habe? Ich habe das nie in Beispielen gesehen.

    
Peter 13.03.2015, 01:54
quelle

5 Antworten

12

Zuerst einige Hintergrundinformationen dazu, wie switch (wirklich) funktioniert:

A switch wird normalerweise als ein Konstrukt betrachtet, das einen Codeabschnitt auswählt, der abhängig vom Wert eines Ausdrucks ausgeführt wird, wie in

%Vor%

Es ist jedoch genauer, wenn Sie sich eine switch als eine Form der berechneten goto -Anweisung vorstellen. Zum Beispiel ist das Folgende vollkommen legal:

%Vor%

Abhängig vom Wert von x springt das Programm entweder zu case 1 oder case 2 (oder nach switch , wenn x weder 1 noch 2 ist).

Ihr Programm wird als C kompiliert (mit Junk-Werten für x und y innerhalb der switch , da die Initialisierungen übersprungen werden), aber nicht als C ++. Der Grund dafür ist, dass C ++ keinen Sprung zu einer case -Markierung erlaubt, um die Initialisierung einer Variablen zu kreuzen. Für einfache Typen wie int ist das Überspringen von int x; erlaubt (da keine Initialisierung involviert ist), aber nicht über int x = 1; .

Die Hauptmotivation für diesen Unterschied besteht wahrscheinlich darin, dass der Sprung zu einer case -Etikette, die eine Initialisierung in C ++ kreuzt, nicht sicher wäre, wenn Konstruktoren beteiligt sind. Wenn beispielsweise C ++ ein case Label nach einer Definition My_class my_object innerhalb eines Bereichs zulassen würde, würde das Springen zu diesem case Label den Konstruktor von my_object überspringen, aber seinen Destruktor immer noch ausführen, wenn der Scope beendet wird.

Die gleichen Einschränkungen gelten für goto in C ++. Sie können es nicht verwenden, um in einen Block zu springen und eine Variableninitialisierung zu überspringen.

Als Randnotiz folgt switch der gleichen allgemeinen Syntax wie if und while . Die Syntax von if , wie im C11-Standard (ISO / IEC 9899: 2011, Abschnitt 6.8.4) angegeben, lautet

  

if (Ausdruck) Anweisung

, während die Syntax von switch

ist
  

switch (Ausdruck) Anweisung

Der einzige Unterschied in Bezug auf die Anweisung (in C - C ++ fügt einige weitere Einschränkungen wie oben erwähnt hinzu) besteht darin, dass case labels (und break ) enthalten dürfen. für eine switch , aber nicht für eine if (es sei denn, die if tritt innerhalb einer switch auf).

Wie bei if können Sie sogar die geschweiften Klammern abbrechen und Code wie folgt schreiben. (Ob das unnötig verwirrend ist, ist eine andere Diskussion.)

%Vor%

Syntaktisch gehören case und default Labels in die gleiche Kategorie wie goto labels. Abschnitt 6.8.1 des C11-Standards hat die folgende Definition:

  

beschriftete Aussage:
   Bezeichner : Anweisung
   Fall Konstantenausdruck : Anweisung    Standard : Anweisung

    
Ulfalizer 13.03.2015, 02:17
quelle
7

Sie können herausfinden, was mit einem einfachen Test passiert:

%Vor%

Dieser Code wird innerhalb einer Funktion mit gcc kompiliert. Der C-Compiler sieht i und y innerhalb eines Blocks deklariert, der durch die geschweiften Klammern begrenzt ist. Die printf -Anweisungen drucken jedoch Junk für i und y , da die Zuweisungen niemals ausgeführt werden. Dies liegt daran, dass eine switch -Anweisung einen Sprung zum case bildet, der dem Ausdruck am Anfang von switch entspricht. Der ausführbare Code zwischen der öffnenden Klammer und dem ersten case kann also nicht erreicht werden. Siehe Warum können Variablen in einer switch-Anweisung nicht deklariert werden? , die nicht genau das gleiche Szenario erklärt, aber eine verwandte Diskussion über die switch -Anweisung hat.

Wenn Sie dies mit aktivierten Warnungen ( gcc -Wall ) kompilieren, erhalten Sie:

%Vor%

Interessanterweise wird der folgende Code ohne Warnungen kompiliert und funktioniert:

%Vor%

Die Variablen werden so gedruckt, wie Sie es erwarten, da sie im Rahmen des Blocks switch deklariert sind, und die Werte in den Abschnitten case , in denen die Ausführung stattfindet. Die Tatsache, dass es in diesem Fall funktioniert, bedeutet nicht, dass es empfohlene Praxis ist. :)

    
lurker 13.03.2015 02:10
quelle
2

Kontrolle kann Anweisungen zwischen dem switch head und dem ersten case Ausdruck erreichen - aber einige andere Kontrollstrukturen müssen es dorthin senden. Zum Beispiel gibt es nichts, was Sie daran hindert, einen Switch und eine Schleife zu verschachteln :

%Vor%

kompiliert ohne irgendwelche Beschwerden von entweder gcc 4.9 oder clang 3.5 im -std=c11 -Modus, wenn die Warnungen so hoch wie sie gehen, und wenn sie ausgeführt wird, druckt:

%Vor%

Fun fact: Wenn die Optimierung aktiviert ist, erzeugen beide Compiler tatsächlich 100% geradlinigen Code:

%Vor%     
zwol 27.04.2015 17:54
quelle
1

Es ist nicht legal, und wenn Sie kompilieren, erhalten Sie eine Reihe von "Kreuze Initialisierung von ..." Fehlern. Es gibt eine wirklich gute Erklärung dafür, was hier vor sich geht: Fehler bei der Initialisierung einer Reihe von Kreuzen

Im Prinzip funktioniert ein Schalterfall, indem man zwischen den case-Anweisungen einen beliebigen Code springt, und es ist nicht erlaubt, über die Initialisierung einer Variablen hinaus zu springen. Es wird technisch legal sein und kompilieren, wenn Sie nur einen Funktionsaufruf zwischen den beiden setzen, obwohl die Funktion nie tatsächlich aufgerufen wird.

%Vor%     
Schiem 13.03.2015 02:12
quelle
0

Ich habe versucht, einen Code ähnlich dem, was Sie fragen, zu kompilieren, es kommt mindestens ein Fehler heraus:

  

Fehler C2360: Initialisierung von 'x' wird von 'case' Label

übersprungen

Ihr extra Code wurde nie ausgeführt, weil nach dem Umschalten die Anweisung 'test' überprüft wird, dann wird es zum entsprechenden Label gehen, Ihr extra Bit Code ist unter keinem Label, deshalb wird es für immer übersprungen.

Warum können Sie vor der switch-Anweisung nicht Ihren zusätzlichen Code einfügen? irgendeinen Grund?

    
V-SHY 13.03.2015 02:09
quelle

Tags und Links