Rob*_*Rob 910 c++ switch-statement
我一直想知道这一点 - 为什么你不能在switch语句中的case标签之后声明变量?在C++中,您可以在任何地方声明变量(并且声明它们接近第一次使用显然是一件好事)但是以下仍然不起作用:
switch (val)
{
case VAL:
// This won't work
int newVal = 42;
break;
case ANOTHER_VAL:
...
break;
}
Run Code Online (Sandbox Code Playgroud)
以上给出了以下错误(MSC):
'case'标签跳过'newVal'的初始化
这似乎也是其他语言的限制.为什么会出现这样的问题?
TJ *_*oks 1097
Case陈述只是标签.这意味着编译器会将其解释为直接跳转到标签.在C++中,这里的问题是范围之一.您的花括号将范围定义为switch语句中的所有内容.这意味着您将留下一个范围,在该范围内将跳过初始化的代码进一步执行跳转.处理此问题的正确方法是定义特定于该case语句的作用域并在其中定义变量.
switch (val)
{
case VAL:
{
// This will work
int newVal = 42;
break;
}
case ANOTHER_VAL:
...
break;
}
Run Code Online (Sandbox Code Playgroud)
AnT*_*AnT 314
这个问题是最初标记为[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;
}
Run Code Online (Sandbox Code Playgroud)添加额外的{}块可以修复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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,即使它现在从C的角度来看是有效的,但从C++的角度来看它仍然是无效的.
对称地,在C++案例中,问题可以很容易地解决,而不需要{}.只需从变量声明中删除初始化程序,代码就会生效
switch (val)
{
case VAL:
int newVal;
newVal = 42;
break;
case ANOTHER_VAL: /* Now it works in C++! */
...
break;
}
Run Code Online (Sandbox Code Playgroud)
请注意,即使它现在从C++的角度来看是有效的,但从C的角度来看它仍然是无效的.
Ric*_*den 133
好.只是为了澄清这一点,严格与宣言无关.它只涉及"跳过初始化"(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;
}
Run Code Online (Sandbox Code Playgroud)
如果对象是非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;
}
Run Code Online (Sandbox Code Playgroud)
此限制不限于switch语句.跳过初始化时使用'goto'也是错误的:
goto LABEL; // Error jumping over initialization
int j = 0;
LABEL:
;
Run Code Online (Sandbox Code Playgroud)
有点琐事是,这是C++和C之间的区别.在C中,跳过初始化并不是错误.
正如其他人所提到的,解决方案是添加嵌套块,以便变量的生命周期仅限于单个案例标签.
Mar*_*ram 35
整个switch语句在同一范围内.要解决它,请执行以下操作:
switch (val)
{
case VAL:
{
// This **will** work
int newVal = 42;
}
break;
case ANOTHER_VAL:
...
break;
}
Run Code Online (Sandbox Code Playgroud)
注意括号.
Jee*_*tel 29
在阅读了所有答案和更多研究后,我得到了一些东西.
Case statements are only 'labels'
Run Code Online (Sandbox Code Playgroud)
在C中,根据规范,
§6.8.1标签声明:
labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
Run Code Online (Sandbox Code Playgroud)
在C中,没有任何条款允许"标记声明".它不是语言的一部分.
所以
case 1: int x=10;
printf(" x is %d",x);
break;
Run Code Online (Sandbox Code Playgroud)
这将无法编译,请参阅http://codepad.org/YiyLQTYw.海湾合作委员会发出错误:
label can only be a part of statement and declaration is not a statement
Run Code Online (Sandbox Code Playgroud)
甚至
case 1: int x;
x=10;
printf(" x is %d",x);
break;
Run Code Online (Sandbox Code Playgroud)
这也没有编译,请参阅http://codepad.org/BXnRD3bu.在这里我也得到了同样的错误.
在C++中,根据规范,
允许使用带标签的声明,但不允许标记为-initialization.
这种情况的解决方案是两个
使用{}使用新范围
case 1:
{
int x=10;
printf(" x is %d", x);
}
break;
Run Code Online (Sandbox Code Playgroud)或者使用带标签的虚拟语句
case 1: ;
int x=10;
printf(" x is %d",x);
break;
Run Code Online (Sandbox Code Playgroud)在switch()之前声明变量,并在case语句中使用不同的值初始化它,如果它满足您的要求
main()
{
int x; // Declare before
switch(a)
{
case 1: x=10;
break;
case 2: x=20;
break;
}
}
Run Code Online (Sandbox Code Playgroud)有关switch语句的更多内容
切勿在交换机中写入任何不属于任何标签的语句,因为它们永远不会执行:
switch(a)
{
printf("This will never print"); // This will never executed
case 1:
printf(" 1");
break;
default:
break;
}
Run Code Online (Sandbox Code Playgroud)
emk*_*emk 20
你不能这样做,因为case标签实际上只是包含块的入口点.
Duff的设备最清楚地说明了这一点.以下是维基百科的一些代码:
strcpy(char *to, char *from, size_t count) {
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
Run Code Online (Sandbox Code Playgroud)
注意case标签如何完全忽略块边界.是的,这是邪恶的.但这就是你的代码示例不起作用的原因.跳转到case标签与使用相同goto,因此不允许使用构造函数跳过局部变量.
正如其他几张海报所表明的那样,你需要自己设置一个块:
switch (...) {
case FOO: {
MyObject x(...);
...
break;
}
...
}
Run Code Online (Sandbox Code Playgroud)
MrZ*_*bra 16
到目前为止,大多数回复在一个方面是错误的:您可以在case语句之后声明变量,但是您无法初始化它们:
case 1:
int x; // Works
int y = 0; // Error, initialization is skipped by case
break;
case 2:
...
Run Code Online (Sandbox Code Playgroud)
如前所述,一个很好的方法是使用大括号为您的案例创建一个范围.
Jer*_*emy 12
我最喜欢的邪恶切换技巧是使用if(0)跳过不需要的案例标签.
switch(val)
{
case 0:
// Do something
if (0) {
case 1:
// Do something else
}
case 2:
// Do something in all cases
}
Run Code Online (Sandbox Code Playgroud)
但非常邪恶.
Dan*_*eld 10
试试这个:
switch (val)
{
case VAL:
{
int newVal = 42;
}
break;
}
Run Code Online (Sandbox Code Playgroud)
如果启动新块,则可以在switch语句中声明变量:
switch (thing)
{
case A:
{
int i = 0; // Completely legal
}
break;
}
Run Code Online (Sandbox Code Playgroud)
原因是在堆栈上分配(和回收)空间以存储局部变量.
考虑:
switch(val)
{
case VAL:
int newVal = 42;
default:
int newVal = 23;
}
Run Code Online (Sandbox Code Playgroud)
在没有break语句的情况下,有时newVal会被声明两次,并且你不知道它是否会在运行时之前发生.我的猜测是限制是因为这种混乱.newVal的范围是什么?公约将规定它将是整个开关块(在支架之间).
我不是C++程序员,但在C:
switch(val) {
int x;
case VAL:
x=1;
}
Run Code Online (Sandbox Code Playgroud)
工作良好.在开关块内声明变量很好.在案件警卫之后宣布不是.