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

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

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

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

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


当前回答

newVal存在于开关的整个作用域中,但只有在VAL分支被命中时才会初始化。如果你在VAL中创建一个代码块,它应该是OK的。

其他回答

好的。我要澄清一下,这和申报完全没有关系。它只涉及“跳过初始化”(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语句中声明变量。试试这个吧:

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

这个问题最初同时被标记为c和c++。原始代码在C和c++中都是无效的,但原因完全不同,互不相关。

In C++ this code is invalid because the case ANOTHER_VAL: label jumps into the scope of variable newVal bypassing its initialization. Jumps that bypass initialization of automatic objects are illegal in C++. This side of the issue is correctly addressed by most answers. However, in C language bypassing variable initialization is not an error. Jumping into the scope of a variable over its initialization is legal in C. It simply means that the variable is left uninitialized. The original code does not compile in C for a completely different reason. Label case VAL: in the original code is attached to the declaration of variable newVal. In C language declarations are not statements. They cannot be labeled. And this is what causes the error when this code is interpreted as C code. switch (val) { case VAL: /* <- C error is here */ int newVal = 42; break; case ANOTHER_VAL: /* <- C++ error is here */ ... break; } Adding an extra {} block fixes both C++ and C problems, even though these problems happen to be very different. On the C++ side it restricts the scope of newVal, making sure that case ANOTHER_VAL: no longer jumps into that scope, which eliminates the C++ issue. On the C side that extra {} introduces a compound statement, thus making the case VAL: label to apply to a statement, which eliminates the C issue. In C case the problem can be easily solved without the {}. Just add an empty statement after the case VAL: label and the code will become valid switch (val) { case VAL:; /* Now it works in C! */ int newVal = 42; break; case ANOTHER_VAL: ... break; } Note that even though it is now valid from C point of view, it remains invalid from C++ point of view. Symmetrically, in C++ case the the problem can be easily solved without the {}. Just remove the initializer from variable declaration and the code will become valid switch (val) { case VAL: int newVal; newVal = 42; break; case ANOTHER_VAL: /* Now it works in C++! */ ... break; } Note that even though it is now valid from C++ point of view, it remains invalid from C point of view.

从C23开始,C语言中的所有标签都将被解释为标签隐含的空语句(N2508),也就是说,在C语言中不能将标签放在声明前面的问题将不再存在,并且不再需要上述基于;的修复。

有趣的是,这很好:

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

case 1:  
    break;
}

... 但这不是:

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

case 1:  
    break;
}

我得到一个修复足够简单,但我不明白为什么第一个例子不打扰编译器。正如之前所提到的(2年前的呵呵),声明不是导致错误的原因,即使有逻辑。初始化是问题所在。如果变量在不同的行上被初始化和声明,它将被编译。

到目前为止,答案都是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();
}