————————————————————————
C++primer:
对于switch结构,只能在它的最后一个case标号或default标号后面定义变量:
case true:
// error:declaration precedes a case label, skipped by case false.
string file_name=get_file_name();
break;
case false:
//…
制定这个规则是为了避免出现代码跳过变量的定义和初始化的情况。回顾变量的作用域,变量从它的定义点开始有效,直到它所在块结束为止。现在考虑如果在两个case标号之间定义变量会出现什么情况。该变量会在块结束之前一直存在。对于定义该变量的标号后面的其他case标号,它们所关联的代码都可以使用这个变量。如果switch从那些后续case标号开始执行,那么这个变量可能还未定义就要使用了。这种情况下,如果需要为某个特殊的case定义变量,则可以引入块语句,在该块语句中定义变量,从而保证这个变量在使用前被定义和初始化。
case true:
{
//ok:declaration statement within a statement block
string file_name=get_file_name();
//…
}
break;
case false:
//…
——————————————————————————————–
上面明确了在switch语句内定义一个变量的时候有三种情况:
(1)可在default中定义;
(1)可在最后一个case中定义;
(3)在某个特殊的case中定义变量,但必须引入块语句。
上面规则出现的原因:
在C++中,switch-case中的case实质上只是一个标签(label),case中的代码并没有构成一个局部作用域,虽然它的缩进好像是一个作用域。即,所有在case里面定义的变量作用域都是switch{…},所以在后面其他case中依然可以访问到这个变量。
举个例子:
- switch (a)
- {
- case 1:
- int m = 1;//(1)编译出错
- break;
- case 2:
- {
- int n = 3;//(2)编译通过,引入块语句
- }
- break;
- case 3:
- int c =3;//(3)编译通过,最后一个case
- cout<<”ss”<<endl;//输出ss
- break;
- }</span>
switch (a)
{
case 1:
int m = 1;//(1)编译出错
break;
case 2:
{
int n = 3;//(2)编译通过,引入块语句
}
break;
case 3:
int c =3;//(3)编译通过,最后一个case
cout<<"ss"<<endl;//输出ss
break;
}</span>
分析:
C++规定:如果一个程序的执行路径从代码中的点A(某个局部变量x还未定义)跳到代码中另一点B(该局部变量x已定义,并且定义的时候有初始化),那么编译器会报错。这样的跳跃可以是由于执行goto语句或是switch-case语句造成的。
上面的程序如果从switch直接跳到case2,就发生了与C++规定不相符的情况。在switch时m还没有定义,但是到达case2后m已经定义,并且被初始化,这样m被直接跳过,编译就会出错。
但是如果把: int m = 1; 改成: int m; 编译就不会出错。原因是跳过声明时不报错,可能会有警告,只有跳过有初始化的声明时才会报错。
如果真的需要在中间某个case里定义变量,则简单的解决办法是引入块语句,在该块语句中定义变量。
之所以在最后一个case和default中可以定义变量,是因为在这里面定义的变量是不可能被其他case引用的,因为其作用域不可能向上扩展。