我一直想知道这一点 - 为什么你不能在 switch 语句中的 case 标签之后声明变量?在 C ++ 中,您可以在任何地方声明变量(并且声明它们接近第一次使用显然是一件好事)但是以下仍然不起作用:
switch (val)
{
case VAL:
// This won't work
int newVal = 42;
break;
case ANOTHER_VAL:
...
break;
}
以上给出了以下错误(MSC):
'case' 标签跳过'newVal' 的初始化
这似乎也是其他语言的限制。为什么会出现这样的问题?
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:
标签应用于语句,从而消除了 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 的角度来看它仍然是无效的。
好。只是为了澄清这一点,严格与宣言无关。它只涉及 “跳过初始化”(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 中,跳过初始化并不是错误。
正如其他人所提到的,解决方案是添加嵌套块,以便变量的生命周期仅限于单个案例标签。