📣🥳🥳🥳📣
✨Hello! 如果这篇【文章】对你有帮助😄,希望可以给博主点个赞👍鼓励一下😘
📣🥳🥳🥳📣
🤔 问题背景
关于switch
语句,我们知道其执行流程有可能会跨过某些case
标签。如果程序跳转到了某个特定的case
,则switch
结构中该case
标签之前的部分会被忽略掉。但是,如果说被略过的代码中包含有某些变量的定义,那会发生什么?
《C++ Primer 5th》163页给出的原文答案是👇
”如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳到后一处的行为是非法行为“。
如果翻回去看P163的例子,会发现例子也有一点点"难以理解"。但其实只需要搞清楚【变量定义】、【变量初始化】以及【变量作用域】这几个概念就可以理顺头绪了。
🌟 问题思考
下面用一个个例子来说明
1️⃣
int main() {
switch (2) {
case 1:
int x;
break;
case 2:
x = 2;
cout << "x=" << x << endl;
break;
}
return 0;
}
对于上面这个例子,程序正常编译,且能正常运行并打印出x=2
。
【原因在于】:在处理switch case语句中,C++11标准的编译器会在执行case
跳转前为变量分配空间。也就是说,编译阶段时,变量x
就已经被成功定义并且获得了对应的内存空间,因此后续令x=2
的语句也就没有什么问题。
通过这个例子我们得知,【变量定义】在编译阶段就已完成,
case 1
只是对变量x
进行了【变量定义】, 但没有执行【变量初始化】操作
2️⃣
int main() {
switch (2) {
case 1:
int x = 1; //note:crosses initialization of 'int x'
break;
case 2:
x = 2; //即使把这句删掉也一样
cout << "x=" << x << endl;
break;
}
return 0;
}
由于switch
大括号内所有case
同属一个【作用域】,C++11标准下规定switch
语句不能出现这样的写法,因为【变量初始化】语句是一个确确实实在程序运行时才会被调用的语句,是可以被case
跳转屏蔽掉的语句。
因此,如果允许了上面这种写法,执行case 2
时x=2
便会出现【变量x尚未被定义】的报错,而编译器提前把这一错误给扼杀在这里。
int main() {
switch (2) {
case 1: { //case 1单独的局部作用域
int x = 1; //可以认为case 1下的语句藏在了一个独立的作用域,'与外面的世界无关'
break;
}
case 2:
x = 2; //error:'x' was not declared in this scope
cout << "x=" << x << endl;
break;
}
return 0;
}
【因此根本原因就是】:int x
是【变量定义】操作,int x = 1
是【变量初始化】操作(当然初始化时刻之前变量也被定义,但对一语句来说如果出现初始化操作则优先定位为初始化语句)。在C++11的标准下,【变量定义】操作在编译阶段就会执行分配内存,而涉及【变量初始化】操作的语句则必须等到程序运行时才会调用执行。
这时候再来看下下面这个例子👇
int main() {
switch (2) {
case 1:
int x = 1; //note:crosses initialization of 'int x'
break;
case 2:
int x = 2; //error:redeclaration of 'int x'
cout << "x=" << x << endl;
break;
}
return 0;
}
结合此前的例子可以很好理解。修改的方法同样是只需要加一对大括号{}
👇
int main() {
switch (2) {
case 1: {
int x = 1;
break;
}
case 2: //此时case 1中的x便和case 2中的x没有关联
int x = 2;
cout << "x=" << x << endl; //正常打印出x=2
break;
}
return 0;
}
但若将{}
放在case 2
,那肯定还会提示crosses initialization of 'int x'
👇
int main() {
switch (2) {
case 1:
int x = 1;
break;
case 2: {
int x = 2; //note:crosses initialization of 'int x'
cout << "x=" << x << endl;
break;
}
}
return 0;
}
【总结】:因此对于switch
语句的使用,如果确实有需要在内部定义变量的场景,最好的方法就是在编程的时候,将整个switch
语句中都用到的变量在switch
外定义好,到了switch
内部,则可以针对某个case
需要单独使用某些变量的情况,用{}
作用域符号来明确此case
语句的作用域
3️⃣
最后,就可以来看看《C++ Primer 5th》P160中的这些例子👇
结合1️⃣2️⃣显然就可以很好理解了。但需额外解释一下string file_name
,虽然该变量看起来没被初始化,但正如文中所说,它被【隐式初始化】了,这是因为string
这个类类型中定义了【隐式初始化】的方法。
✨如有问题欢迎在底下评论留言或私信!
如果这篇【文章】对你有帮助😄,希望可以给博主【点个赞👍】鼓励一下😘
❤️Thanks for your encouragement❤️