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

我一直想知道-为何您不能在switch语句中的case标签以后声明变量? 在C ++中,您几乎能够在任何地方声明变量(而且声明它们接近首次使用显然是一件好事),但如下操做仍然无效: ios

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

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

“ newVal”的初始化被“ case”标签跳过 scala

这彷佛也是其余语言的限制。 为何会有这样的问题? code


#1楼

C ++ Standard具备:能够传输到块中,但不能以初始化绕过声明的方式进行。 除非变量具备POD类型(3.9)且声明时没有初始化程序(8.5),不然该程序将从具备自动存储持续时间的局部变量不在范围内的点跳转到其处于范围内的点的格式不正确。 orm

用来讲明此规则的代码: 对象

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

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

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

#2楼

到目前为止,答案一直是C ++。 it

对于C ++,您不能跳过初始化。 您能够在C中使用。可是,在C中,声明不是语句,而且大小写标签后面必须带有语句。 io

所以,有效(但难看)的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();
}

#3楼

彷佛能够在switch 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;
}

#4楼

这个问题 最初标记为[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角度来看它仍然无效。


#5楼

我只是想强调苗条观点 。 开关构造可建立一个完整的一流公民范围。 所以,能够在第一个case标签以前的switch语句中声明(并初始化)变量, 而无需附加的括号对:

switch (val) {  
  /* This *will* work, even in C89 */
  int newVal = 42;  
case VAL:
  newVal = 1984; 
  break;
case ANOTHER_VAL:  
  newVal = 2001;
  break;
}
相关文章
相关标签/搜索