为什么不能在 switch 语句中声明变量?

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

答案

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

这个问题最初标记为 [C] 和 [C ++] 在同一时间。原始代码确实在 C 和 C ++ 中都是无效的,但是出于完全不同的不相关原因。

  • 在 C ++ 中,此代码无效,因为case ANOTHER_VAL:标签跳过了初始化而跳入了变量newVal的范围。在 C ++ 中,绕过自动对象初始化的跳转是非法的。大多数回答正确地解决了问题的这一方面。

  • 但是,在 C 语言中,绕过变量初始化不是错误。在 C 语言中,跳过变量的初始化范围是合法的。这仅表示该变量未初始化。出于完全不同的原因,原始代码无法在 C 中编译。标签case VAL:在原始代码中附加到变量newVal的声明中。在 C 语言中,声明不是语句。它们不能被标记。而当将此代码解释为 C 代码时,这就是导致错误的原因。

    switch (val)  
    {  
    case VAL:             /* <- C error is here */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:     /* <- C++ error is here */
      ...
      break;
    }

添加一个额外的{}块可以解决 C ++ 和 C 问题,即使这些问题恰好有很大不同。在 C ++ 方面,它限制了newVal的范围,确保case ANOTHER_VAL:不再跳入该范围,从而消除了 C ++ 问题。在 C 方面,多余的{}引入了复合语句,从而使case VAL:标签适用于一条语句,从而消除了 C 问题。

  • 在 C 情况下,无需使用{}即可轻松解决问题。只需在case VAL:标签后添加一个空语句,代码便会有效

    switch (val)  
    {  
    case VAL:;            /* Now it works in C! */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:  
      ...
      break;
    }

    请注意,即使从 C 的角度来看它现在是有效的,但从 C ++ 的角度来看它仍然是无效的。

  • 对称地,在 C ++ 情况下,无需使用{}即可轻松解决问题。只需从变量声明中删除初始化程序,代码将变为有效

    switch (val)  
    {  
    case VAL: 
      int newVal;
      newVal = 42;  
      break;
    case ANOTHER_VAL:     /* Now it works in C++! */
      ...
      break;
    }

    请注意,即使从 C ++ 的角度来看它现在是有效的,但从 C 的角度来看它仍然是无效的。

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' initialized to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}
class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}
goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;
switch (val)
{
    case VAL:
    {
        // This **will** work
        int newVal = 42;
    }
    break;

    case ANOTHER_VAL:
      ...
    break;
}
Case statements are only 'labels'
labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement
case 1: int x=10;
        printf(" x is %d",x);
break;
label can only be a part of statement and declaration is not a statement
case 1: int x;
          x=10;
            printf(" x is %d",x);
    break;
switch(a)
{
    printf("This will never print"); // This will never executed

    case 1:
        printf(" 1");
        break;

    default:
        break;
}
strcpy(char *to, char *from, size_t count) {
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}
switch (...) {
    case FOO: {
        MyObject x(...);
        ...
        break; 
    }
    ...
 }
case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...
switch(val)
{
case 0:
// Do something
if (0) {
case 1:
// Do something else
}
case 2:
// Do something in all cases
}
switch (val)
{
    case VAL:
    {
        int newVal = 42;
    }
    break;
}
switch (thing)
{ 
  case A:
  {
    int i = 0;  // Completely legal
  }
  break;
}