1149 Stimmen

Warum können Variablen nicht in einer switch-Anweisung deklariert werden?

Ich habe mich schon immer gefragt, warum man Variablen nicht nach einem Case-Label in einer switch-Anweisung deklarieren kann. I

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

Dies führt zu der folgenden Fehlermeldung (MSC):

Initialisierung von 'newVal' wird durch 'case'-Etikett übersprungen

Dies scheint auch in anderen Sprachen eine Einschränkung zu sein. Warum ist dies ein solches Problem?

7voto

Seb Rose Punkte 3568

Sie können Variablen innerhalb einer switch-Anweisung deklarieren wenn beginnen Sie einen neuen Block:

switch (thing)
{ 
  case A:
  {
    int i = 0;  // Completely legal
  }
  break;
}

Der Grund dafür ist die Zuweisung (und Wiedergewinnung) von Speicherplatz auf dem Stack für die Speicherung der lokalen Variablen.

4voto

Der gesamte Abschnitt des Schalters ist ein einziger Deklarationskontext. Sie können eine Variable nicht in einer solchen case-Anweisung deklarieren. Versuchen Sie stattdessen dies:

switch (val)  
{  
case VAL:
{
  // This will work
  int newVal = 42;
  break;
}
case ANOTHER_VAL:  
  ...
  break;
}

4voto

PcAF Punkte 1964

Ich schrieb diese Antwort ursprünglich für diese Frage . Als ich sie jedoch fertiggestellt hatte, stellte ich fest, dass die Antwort bereits geschlossen wurde. Also habe ich sie hier gepostet, vielleicht findet sie jemand, der sich gerne auf Standards bezieht, hilfreich.

Der betreffende Originalcode:

int i;
i = 2;
switch(i)
{
    case 1: 
        int k;
        break;
    case 2:
        k = 1;
        cout<<k<<endl;
        break;
}

Es gibt eigentlich 2 Fragen:

1. Warum kann ich eine Variable deklarieren nach case Etikett?

Das liegt daran, dass in C++ das Etikett in Form sein muss:

N3337 6.1/1

beschriftete Aussage:

...

  • attribut-specifier-seqopt case constant-expression : statement

...

Und in C++ Deklarationserklärung wird auch betrachtet als Anweisung (im Gegensatz zu C ):

N3337 6/1:

Anweisung :

...

Deklaration-Aussage

...

2. Warum kann ich eine Variablendeklaration überspringen und sie dann verwenden?

Weil: N3337 6.7/3

Es ist möglich, in einen Block zu wechseln, aber nicht so, dass Deklarationen mit Initialisierung umgangen werden . A Programm, das springt (Die Übertragung von den Zustand eines switch-Anweisung an ein Case-Label wird als Sprung betrachtet in dieser Hinsicht).

von einem Punkt, an dem eine Variable mit automatischer Speicherdauer nicht in den Anwendungsbereich fällt, zu einem Punkt, an dem sie in den Anwendungsbereich fällt, ist schlecht geformt es sei denn, die Variable ist skalarer Art Klassenart mit trivialem Standard Konstruktor und einem trivialen Destruktor, eine cv-qualifizierte Version eines dieser Typen oder ein Array von einem der Typs und wird ohne Initialisierer deklariert (8.5).

Desde k ist von Skalartyp und zum Zeitpunkt der Deklaration nicht initialisiert ist, ist ein Überspringen der Deklaration möglich. Dies ist semantisch äquivalent:

goto label;

int x;

label:
cout << x << endl;

Das wäre jedoch nicht möglich, wenn x wurde zum Zeitpunkt der Deklaration initialisiert:

 goto label;

    int x = 58; //error, jumping over declaration with initialization

    label:
    cout << x << endl;

3voto

Wenn Ihr Code sagt "int newVal=42", dann würden Sie vernünftigerweise erwarten, dass newVal niemals uninitialisiert ist. Wenn Sie jedoch zu dieser Anweisung springen (was Sie gerade tun), passiert genau das - newVal ist zwar im Gültigkeitsbereich, wurde aber noch nicht zugewiesen.

Wenn Sie das wirklich beabsichtigt haben, dann muss die Sprache dies explizit machen, indem Sie sagen "int newVal; newVal = 42;". Andernfalls können Sie den Geltungsbereich von newVal auf den Einzelfall beschränken, was wahrscheinlich das ist, was Sie wollten.

Vielleicht wird es klarer, wenn Sie das gleiche Beispiel mit "const int newVal = 42;" betrachten.

3voto

Ich wollte nur betonen schlank 's Punkt . Ein switch-Konstrukt erzeugt einen ganzen, erstklassigen Bereich. Es ist also möglich, eine Variable in einer switch-Anweisung vor dem ersten case-Label zu deklarieren (und zu initialisieren), ohne ein zusätzliches Klammerpaar:

switch (val) {  
  /* This *will* work, even in C89 */
  int newVal = 42;  
case VAL:
  newVal = 1984; 
  break;
case ANOTHER_VAL:  
  newVal = 2001;
  break;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X