我看到了一些令人惊讶的代码:
#include <iostream>
using namespace std;
int main() {
// your code goes here
auto myDummy = [](int i){
switch(i){
case 0: return 0;
case 1:{
std::cout << "Evaluated 1\n";
if(i == 1){
return 1;
}
case 2:
std::cout << "Evaluated 2\n";
return 2;
}
break;
default: return -1;
}
};
std::cout << myDummy(1) << "\n";
return 0;
}
它在没有警告的情况下编译和运行。案例1 {}的括号似乎被忽略了。
myDummy(1)
- &GT; 1
myDummy(2)
- &GT; 2
如果我将案例1的代码修改为:
case 1:{
std::cout << "Evaluated 1\n";
int a = i;
if(a == 1){
return 1;
}
case 2:
std::cout << "Evaluated 2\n";
return 2;
}
break;
然后它不再编译:
prog.cpp:16:13:错误:跳转到案例标签[-fpermissive]
case 2: ^ prog.cpp:12:21: note: crosses initialization of 'int a' int a = i;
案例1的括号:{}中断;不要取消开关上下文。它只是为变量创建了一个局部范围。 但这真的很混乱。 为什么会出现这种行为?
答案 0 :(得分:3)
以下是关于switch
(§6.4.2,强调我的)标准的说法:
2 - 任何声明 开关 声明可以用一个或多个案例标签标记为 如下: 案件 常数表达式 : 在哪里 常数表达式 应该是转换的常量表达式( 5.19 )推广类型的 切换条件。
&LT; ...&GT;
5 - 当 开关 执行语句,评估其条件并与每个案例常量进行比较。如果 其中一个case常量等于condition的值,control被传递给下面的语句 匹配的案例标签
因此switch
并不关心案件的确切位置,以下是有效的:
int main() {
int i = 0;
switch(i)
{
case 1:
{
case 2:
{
if(false)
{
case 0:
std::cout << "hello there!"; //yes it will print
}
}
}
}
return 0;
}
关于您提出的修改,请查看我对this question的回答。基本上用
case 1:{
std::cout << "Evaluated 1\n";
int a = i;
if(a == 1){
return 1;
}
case 2:
//here a is in scope
std::cout << "Evaluated 2\n";
return 2;
}
您可以跳转到case2
而无需实际创建a
,但a
仍然在范围内。
答案 1 :(得分:2)
您可以在任何地方放置范围:
int main() {
int a;
{
int a; // in a more local scope.
}
}
但是你不能把变量初始化放在一个范围内,超过2个开关可以看到它:
int main() {
int b;
switch(1) {
case 0:
int a = 0; // error
break;
case 1:
b = a; // what happens?
break;
}
}
最后,在另一个范围内的案例标签没有任何问题(只要它不违反我们的第二个规则,那里):
int main() {
switch(1) {
case 1: {
break;
case 2:
break;
}
}
}
答案 2 :(得分:2)
switch
与标签的工作方式与goto
的标签相同。
采用这样的方案时应该小心,特别是在读取未初始化的变量时,其行为是未定义的。