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

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

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

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

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


当前回答

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

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。

其他回答

我相信手头的问题是,这是声明被跳过,你试图在其他地方使用var,它不会被声明。

c++标准有: 可以将其转移到块中,但不能绕过带有初始化的声明。如果一个程序从一个具有自动存储持续时间的局部变量不在作用域中的点跳转到它在作用域中的点,那么该程序就是病态形式的,除非该变量具有POD类型(3.9),并且声明时没有初始化式(8.5)。

说明此规则的代码:

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

显示初始化器效果的代码:

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

匿名对象似乎可以在switch case语句中声明或创建,因为它们不能被引用,因此不能进入下一个case。考虑这个例子是在GCC 4.5.3和Visual Studio 2008上编译的(可能是一个遵从性问题,所以请专家们权衡一下)

#include <cstdlib>

struct Foo{};

int main()
{
    int i = 42;

    switch( i )
    {
    case 42:
        Foo();  // Apparently valid
        break;

    default:
        break;
    }
    return EXIT_SUCCESS;
}

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

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

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

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

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

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