为什么不能在switch语句中声明变量?
我一直在想这个 - 为什么你不能在switch语句的case标签后面声明变量? 在C ++中,你可以在任何地方声明变量(并且声明它们接近第一次使用显然是一件好事),但以下内容仍然不起作用:
switch (val)
{
case VAL:
// This won't work
int newVal = 42;
break;
case ANOTHER_VAL:
...
break;
}
以上给我以下错误(MSC):
'newVal'的初始化由'case'标签跳过
这似乎也是其他语言的限制。 为什么会出现这样的问题?
Case
陈述只是标签 。 这意味着编译器会将其解释为直接跳转到标签。 在C ++中,这里的问题是范围之一。 您的大括号将范围定义为switch
语句内的所有内容。 这意味着你只剩下一个范围,在该范围内跳过代码进一步执行跳过初始化的代码。 处理这种情况的正确方法是定义特定于该case
语句的范围并在其中定义您的变量。
switch (val)
{
case VAL:
{
// This will work
int newVal = 42;
break;
}
case ANOTHER_VAL:
...
break;
}
这个问题同时被标记为[C]和[C ++]。 原始代码在C和C ++中都是无效的,但是完全不同的不相干的原因。 我相信这个重要的细节被现有的答案遗漏了(或混淆了)。
在C ++中,这个代码是无效的,因为case ANOTHER_VAL:
label跳转到变量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:
label消除了C问题。
在C情况下,如果没有{}
,问题很容易解决。 在case VAL:
label和代码将变为有效之后,只需添加一个空语句
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的角度来看,它仍然是无效的。
好。 只是为了澄清这与声明严格无关。 它只涉及“跳过初始化”(ISO C ++ '03 6.7 / 3)
这里的很多帖子都提到跳过声明可能会导致变量“未声明”。 这不是真的。 POD对象可以在没有初始化器的情况下声明,但是它会有一个不确定的值。 例如:
switch (i)
{
case 0:
int j; // 'j' has indeterminate value
j = 0; // 'j' 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中,跳过初始化不是错误。
正如其他人所提到的,解决方案是添加一个嵌套块,以便变量的生存期限于个别情况标签。
链接地址: http://www.djcxy.com/p/273.html