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

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

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

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

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


当前回答

您不能这样做,因为case标签实际上只是包含块的入口点。

达夫的装置最清楚地说明了这一点。以下是一些来自维基百科的代码:

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

请注意大小写标签是如何完全忽略块边界的。是的,这是邪恶的。但这就是为什么您的代码示例不起作用。跳转到case标签与使用goto相同,因此不允许跳过带有构造函数的局部变量。

正如其他几张海报所指出的那样,你需要放入自己的方块:

switch (...) {
    case FOO: {
        MyObject x(...);
        ...
        break; 
    }
    ...
 }

其他回答

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

如果你的代码说“int newVal=42”,那么你可以合理地期望newVal永远不会是未初始化的。但是如果你浏览这条语句(这就是你正在做的),那么就会发生这样的事情——newVal在作用域内,但没有被分配。

如果这是你真正想要发生的,那么语言需要通过“int newVal;newVal = 42;"。否则,您可以将newVal的范围限制为单个情况,这更可能是您想要的结果。

如果你考虑相同的例子,但加上"const int newVal = 42;"

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

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。

我只是想强调斯利姆的观点。转换构造创建了一个完整的、一等公民的范围。因此,可以在switch语句中在第一个case标签之前声明(并初始化)一个变量,而不需要额外的括号对:

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

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