转:switch内部的变量定义问题(goto类似)

自我总结:(之前查过goto和switch的资料但是一直没有搞懂,直到今天看到这个讨论才懂了)

1   int a;    是个描述,而不是个命令,只是说明我需要空间,编译器会保证在相应的作用域之中这个变量的空间是被分配了(只要改一下堆栈指针就好)。

2   大部分编译期实现会选择在函数开始把所有局部变量的空间都分配好。

3   声明还可以是一个类的对象,那么这时候这个声明的语句就很可能是一个命令了:调用相应的构造函数。这种情况下,编译器就会告诉你跳过了该做的事情,不能这么写了。

 

 

之前我的错误理解和这个形容是一样的:

vczh(作者) 回复 yksgj
你觉得编译器产生的代码,有可能真的是运行到int ival;这一行,就给你的stack立刻涨多4个字节,运行到}就立刻退回去吗?




原问题:http://www.zhihu.com/question/23051685

请教switch内部的变量定义问题?

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     bool b = false;
 7 
 8     switch (false)
 9     {
10         case true:
11             int ival;
12             break;
13 
14         case false:
15             ival = 3;
16             cout << ival << endl;
17     }
18 
19     return 0;
20 }

 

这段c++代码应该直接执行switch语句中的 case false,这样的话ival应该没有被定义,为什么程序能被编译通过,并顺利执行?(编译器gcc4.7)
这边的ival应该是局部变量,应该运行时在栈上分配空间啊,那么应该不存在在编译时已经分配好空间的问题了吧?

 

 

回答:

---------------------------------------------------------------------------

vczh专业造轮子 gaclib.net

不能跳过的不是变量的定义,而是初始化。你把int ival改成int ival=0;或者string ival,你就可以看到效果。

 

这个我明白,如果string ival的话,必须用花括号括起来才行。可是变量不是应该先定义才能使用吗,为什么这边可以直接跳过定义?
昨天 19:16   
vczh(作者) 回复 yksgj
“定义”不做任何事情,当然可以跳过。只有你初始化了,编译器才会给你产生代码,所以不能跳过。switch的case和goto是一个道理。
昨天 19:17   
yksgj 回复 vczh(作者)
那是不是在编译阶段,实际上已经为ival分配了存储空间?可是在这边ival不是局部变量吗
昨天 19:21   
vczh(作者) 回复 yksgj
你觉得编译器产生的代码,有可能真的是运行到int ival;这一行,就给你的stack立刻涨多4个字节,运行到}就立刻退回去吗?
昨天 19:22   
郑贤伟 回复 yksgj
这个在编译的时候,已经确定了的,系统会计算当前有多少个局部变量,然后统一开辟空间。
系统分配堆栈空间的时候,不是运行时才确定有多少空间需要分配的。
昨天 19:22   
yksgj 回复 vczh(作者)
你的意思是编译器虽然没有给 ival分配空间,但是为它在栈山保留了空间,所以实际上等于定义了ival,是这个意思么?
昨天 19:26   
yksgj 回复 郑贤伟
所以等于在编译阶段还是定义了ival?
昨天 19:28   
vczh(作者) 回复 yksgj
是,其实所有变量的空间都是一进函数就分配好的了,区别只是有没有在那块东西上运行构造函数
昨天 19:28   
郑贤伟 回复 yksgj
是的
昨天 19:28   
yksgj 回复 vczh(作者)
明白了,谢谢轮子哥!
昨天 19:28   
yksgj 回复 郑贤伟
谢谢!
昨天 19:29   
看看汇编代码就知道怎么回事,ival在编译时确定地址为-4(%ebp),ebp作为stack frame
昨天 20:26   
durow 回复 郑贤伟
正解!
昨天 22:27   
这种情况是否说明:内置类型没有初始化可以使用,自定义的类类型必须初始化才能使用? @vczh@郑贤伟 谢谢
昨天 23:22   
vczh(作者) 回复 tor vec
你只要没有构造函数和析构函数,并且你的struct的成员也都没有,那就跟内置的类型一样
昨天 23:37   
tor vec 回复 vczh(作者)
谢谢,我刚刚按你说的试了,确实可以。(另外有成员也是可以的,我用的VS2010)大神怎么一直在线啊
昨天 23:40   
vczh(作者) 回复 tor vec
因为我喜欢宅在家里
 

----------------------------------------------------------------------------

pansz自由软件开发者

ival是局部变量,作用域是所在的大括号内。

所以第二个case仍然属于该变量的作用域。

另外,变量的定义不是语句,所以无需执行也是全范围有效。这里第一个case的语句虽然没有被执行,但它的变量定义仍然有效。

同vczh说的一样,能跳过的是变量初始化而不是变量定义。变量无论在何处定义都有效,switch只能跳过变量初始化,不能跳过变量定义。

 

 

----------------------------------------------------------------------------

刘城不要上zhihu了!

你的理解有一些误区,变量的声明和定义的作用是在静态域,与是否执行到没有关系。定义变量并不存在执行动作。

为什么这个容易误解呢,因为c语言switch语句设计的比较悲剧,每个case部分是没有独立的作用域的。要理解它,一种方法是把它当作goto来看。 比如这个程序就是:

 

 1 #include <iostream>
 2 using namespace std;
 3 int main() {
 4     bool b = false;
 5     goto case_false;
 6 case_true:
 7     int ival;
 8     goto switch_end;
 9 case_false:
10     ival = 3;
11     cout << ival << endl;
12 switch_end:
13     return 0;
14 }

再说一下动态分配的事情,先说清楚分配不是有一条指令教int xxx,执行到这里的时候会分配空间,这个是个描述,而不是个命令,只是说明我需要空间,编译器会保证在相应的作用域之中这个变量的空间是被分配了。
大部分编译期实现会选择在函数开始把所有局部变量的空间都分配好(只要改一下堆栈指针就好)。

最后补充一下,你的声明还可以是一个类的对象,那么这时候这个声明的语句就很可能是一个命令了:调用相应的构造函数。这种情况下,编译器就会告诉你跳过了该做的事情,不能这么写了。

posted @ 2014-03-16 00:44  kira2will  阅读(625)  评论(0编辑  收藏  举报