我一直在想这个问题——为什么不能在switch语句的case标签后面声明变量呢?在c++中,你可以在任何地方声明变量(并且在第一次使用时声明它们显然是一件好事),但以下仍然不能工作:

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

上面给了我以下错误(MSC):

'newVal'的初始化被'case'标签跳过

这在其他语言中似乎也是一个限制。为什么这是一个问题?


当前回答

Case语句只是标签。这意味着编译器将把它解释为直接跳转到标签。在c++中,这里的问题是作用域问题。花括号将作用域定义为switch语句中的所有内容。这意味着您留下了一个作用域,在这个作用域中,将跳过初始化进一步跳转到代码中。

正确的处理方法是定义一个特定于case语句的作用域,并在其中定义变量:

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

其他回答

如果你开始一个新块,你可以在switch语句中声明变量:

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

原因是与在堆栈上分配(和回收)空间以存储局部变量有关。

好的。我要澄清一下,这和申报完全没有关系。它只涉及“跳过初始化”(ISO c++ '03 6.7/3)

这里的许多帖子都提到跳过声明可能会导致变量“未被声明”。这是不对的。POD对象可以在没有初始化式的情况下声明,但它将具有不确定的值。例如:

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' set (not 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;
}

当对象是非pod或聚合时,编译器会隐式地添加一个初始化式,因此不可能跳过这样的声明:

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;
}

这种限制并不局限于switch语句。使用'goto'跳过初始化也是一个错误:

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

一个小细节是,这是c++和C之间的区别。在C中,跳过初始化并不是错误。

正如其他人所提到的,解决方案是添加一个嵌套块,以便变量的生命周期被限制为单个case标签。

到目前为止,大多数回复在一个方面是错误的:你可以在case语句之后声明变量,但你不能初始化它们:

case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...

如前所述,解决这个问题的一个好方法是使用大括号为案例创建作用域。

在阅读了所有的答案和更多的研究之后,我得到了一些东西。

Case statements are only 'labels'

在C语言中,根据规范,

§6.8.1标签声明:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

在C语言中,没有任何子句允许“标记声明”。这不是语言的一部分。

So

case 1: int x=10;
        printf(" x is %d",x);
break;

这将不会编译,请参阅http://codepad.org/YiyLQTYw。GCC给出一个错误:

label can only be a part of statement and declaration is not a statement

Even

  case 1: int x;
          x=10;
            printf(" x is %d",x);
    break;

这也不是编译,参见http://codepad.org/BXnRD3bu。这里我也得到了同样的错误。


在c++中,根据规范,

允许标记-声明,但不允许标记-初始化。

见http://codepad.org/ZmQ0IyDG。


这种情况的解是二

使用{}使用新的作用域 案例1: { int x = 10; Printf (" x是%d", x); } 打破; 或者使用带标签的虚拟语句 案例1:; int x = 10; Printf (" x是%d",x); 打破; 在switch()之前声明变量,并在case语句中用不同的值初始化它,如果它满足您的要求 main () { int x;//在前面声明 开关(a) { 情况1:x=10; 打破; 情况2:x=20; 打破; } }


还有更多关于switch语句的东西

永远不要在switch中写入任何不属于任何标签的语句,因为它们永远不会被执行:

switch(a)
{
    printf("This will never print"); // This will never executed

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

    default:
        break;
}

见http://codepad.org/PA1quYX3。

到目前为止,答案都是c++。

对于c++,你不能跳过初始化。但是,在C语言中,声明不是语句,大小写标签后面必须跟着语句。

所以,有效(但丑陋)的C,无效的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();
}

相反,在c++中,声明是一个语句,因此下面的语句是有效的c++,无效的C

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