我一直在想这个问题——为什么不能在switch语句的case标签后面声明变量呢?在c++中,你可以在任何地方声明变量(并且在第一次使用时声明它们显然是一件好事),但以下仍然不能工作:
switch (val)
{
case VAL:
// This won't work
int newVal = 42;
break;
case ANOTHER_VAL:
...
break;
}
上面给了我以下错误(MSC):
'newVal'的初始化被'case'标签跳过
这在其他语言中似乎也是一个限制。为什么这是一个问题?
一个switch块不同于一连串的if/else if块。我很惊讶没有其他答案能解释清楚。
考虑下面的switch语句:
switch (value) {
case 1:
int a = 10;
break;
case 2:
int a = 20;
break;
}
这可能令人惊讶,但编译器不会将其视为简单的if/else if。它将生成以下代码:
if (value == 1)
goto label_1;
else if (value == 2)
goto label_2;
else
goto label_end;
{
label_1:
int a = 10;
goto label_end;
label_2:
int a = 20; // Already declared !
goto label_end;
}
label_end:
// The code after the switch block
case语句被转换为标签,然后用goto调用。括号创建了一个新的作用域,现在很容易看出为什么不能在一个开关块中声明两个具有相同名称的变量。
它可能看起来很奇怪,但是支持fallthrough是必要的(也就是说,不使用break让执行继续到下一个case)。
好的。我要澄清一下,这和申报完全没有关系。它只涉及“跳过初始化”(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标签。
到目前为止,答案都是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();
}