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?

3voto

Peter Punkte 961

Bislang waren die Antworten für C++.

In C++ kann eine Initialisierung nicht übersprungen werden. In C ist das möglich. Allerdings ist in C eine Deklaration keine Anweisung, und auf Case Labels müssen Anweisungen folgen.

Also, gültiges (aber hässliches) C, ungültiges C++

switch (something)
{
  case 1:; // Ugly hack empty statement
    int i = 6;
    do_stuff_with_i(i);
    break;
  case 2:
    do_something();
    break;
  default:
    get_a_life();
}

Umgekehrt ist in C++ eine Deklaration eine Anweisung, so dass das Folgende in C++ gültig und in C ungültig ist

switch (something)
{
  case 1:
    do_something();
    break;
  case 2:
    int i = 12;
    do_something_else();
}

3voto

Dan Punkte 31

Interessant, dass dies in Ordnung ist:

switch (i)  
{  
case 0:  
    int j;  
    j = 7;  
    break;  

case 1:  
    break;
}

... aber das ist es nicht:

switch (i)  
{  
case 0:  
    int j = 7;  
    break;  

case 1:  
    break;
}

Ich verstehe, dass eine Korrektur einfach genug ist, aber ich verstehe noch nicht, warum das erste Beispiel den Compiler nicht stört. Wie bereits erwähnt wurde (2 Jahre zuvor hehe), Erklärung ist nicht die Ursache des Fehlers, auch wenn die Logik stimmt. Die Initialisierung ist das Problem. Wenn die Variable initialisiert und in den verschiedenen Zeilen deklariert wird, wird sie kompiliert.

2voto

Dalmas Punkte 25939

A switch Block ist nicht dasselbe wie eine Abfolge von if/else if Blöcke. Ich bin überrascht, dass keine andere Antwort es klar erklärt.

Bedenken Sie dies switch Erklärung :

switch (value) {
    case 1:
        int a = 10;
        break;
    case 2:
        int a = 20;
        break;
}

Es mag überraschen, aber der Compiler wird es nicht als eine einfache if/else if . Es wird der folgende Code erzeugt:

if (value == 1)
    goto label_1;
else if (value == 2)
    goto label_2;
else
    goto label_end;

{
label_1:
    int a = 10;
    goto label_end;
label_2:
    int a = 20; // Already declared !
    goto label_end;
}

label_end:
    // The code after the switch block

El case Anweisungen werden in Bezeichnungen umgewandelt und dann mit goto . Durch die Klammern wird ein neuer Bereich geschaffen, und es ist nun leicht zu erkennen, warum man nicht zwei Variablen mit demselben Namen innerhalb einer Variablen deklarieren kann. switch Block.

Es mag seltsam aussehen, aber es ist notwendig, um die durchfallen (d.h. keine Verwendung von break um die Ausführung mit der nächsten case ).

0voto

Neue Variablen können nur im Blockbereich dekaliert werden. Y

case VAL:  
  // This will work
  {
  int newVal = 42;  
  }
  break;

Natürlich hat newVal nur innerhalb der geschweiften Klammern Geltung...

Prost, Ralph

0voto

Jingguo Yao Punkte 6278

C++ Standard hat: Es ist möglich, in einen Block zu wechseln, aber nicht auf eine Weise, die Deklarationen mit Initialisierung umgeht. Ein Programm, das von einem Punkt, an dem eine lokale Variable mit automatischer Speicherdauer nicht im Gültigkeitsbereich ist, zu einem Punkt springt, an dem sie im Gültigkeitsbereich ist, ist nicht formgerecht, es sei denn, die Variable hat den Typ POD (3.9) und ist ohne Initialisierung deklariert (8.5).

Der Code zur Veranschaulichung dieser Regel:

#include <iostream>

using namespace std;

class X {
  public:
    X() 
    {
     cout << "constructor" << endl;
    }
    ~X() 
    {
     cout << "destructor" << endl;
    }
};

template <class type>
void ill_formed()
{
  goto lx;
ly:
  type a;
lx:
  goto ly;
}

template <class type>
void ok()
{
ly:
  type a;
lx:
  goto ly;
}

void test_class()
{
  ok<X>();
  // compile error
  ill_formed<X>();
}

void test_scalar() 
{
  ok<int>();
  ill_formed<int>();
}

int main(int argc, const char *argv[]) 
{
  return 0;
}

Der Code, der die Wirkung des Initialisierers zeigt:

#include <iostream>

using namespace std;

int test1()
{
  int i = 0;
  // There jumps fo "case 1" and "case 2"
  switch(i) {
    case 1:
      // Compile error because of the initializer
      int r = 1; 
      break;
    case 2:
      break;
  };
}

void test2()
{
  int i = 2;
  switch(i) {
    case 1:
      int r;
      r= 1; 
      break;
    case 2:
      cout << "r: " << r << endl;
      break;
  };
}

int main(int argc, const char *argv[]) 
{
  test1();
  test2();
  return 0;
}

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