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

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

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

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

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

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

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

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

 #include <iostream>
using namespace std; int main()
{
bool b = false; switch (false)
{
case true:
int ival;
break; case false:
ival = ;
cout << ival << endl;
} return ;
}

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

回答:

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

vczh专业造轮子 http://www.gaclib.net

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

这个我明白,如果string ival的话,必须用花括号括起来才行。可是变量不是应该先定义才能使用吗,为什么这边可以直接跳过定义?
昨天 19:16   

vczh(作者) 回复 yksgj
“定义”不做任何事情,当然可以跳过。只有你初始化了,编译器才会给你产生代码,所以不能跳过。switch的case和goto是一个道理。
昨天 19:17   1 赞

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   1 赞

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来看。 比如这个程序就是:

 #include <iostream>
using namespace std;
int main() {
bool b = false;
goto case_false;
case_true:
int ival;
goto switch_end;
case_false:
ival = ;
cout << ival << endl;
switch_end:
return ;
}

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

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

转:switch内部的变量定义问题(goto类似)的更多相关文章

  1. C++ Prime:switch内部的变量定义

    如果需要为某个case分支定义并初始化一个变量,我们应该把变量定义在块内,从而确保后面的所有case标签都在变量的作用域之外. case true: { // 正确,声明语句位于语句块内部 strin ...

  2. C# 多线程调用静态方法或者静态实例中的同一个方法-方法内部的变量是线程安全的

    C#  多线程调用静态方法或者静态实例中的同一个方法-方法内部的变量是线程安全的 using System;using System.Threading;using System.Threading. ...

  3. Switch选择语句能否作用在String【字符串】上,也就是能否这么写:Switch(一个字符串变量)?

    Switch选择语句能否作用在String[字符串]上,也就是能否这么写:Switch(一个字符串变量)? 解答:不可以,只能处理int,byte,short,char,(其实是只能处理int,其它三 ...

  4. 函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!闭包访问局部变量

    函数内部声明变量的时候,一定要使用var命令.如果不用的话,你实际上声明了一个全局变量! function f1(){ n=999; } f1(); alert(n); 子函数可以一层一层读取到父元素 ...

  5. shell-的bash内部命令变量介绍与shift等

    一:shell的bash内部命令变量介绍与shift等 1. bash内部变量     有些内部命令在目录列表时是看不见的,他们有shell本身提供,常用的内部命令有:echo,eval,exec,e ...

  6. 《Go学习笔记 . 雨痕》流程控制(if、switch、for range、goto、continue、break)

    Go 精简(合并)了流控制语句,虽然某些时候不够便捷,但够用. if...else... 条件表达式值必须是布尔类型,可省略括号,且左花括号不能另起一行. func main() { x := 3 i ...

  7. 2_C语言中的数据类型 (九)逻辑运算符与if语句、switch、条件运算符?、goto语句与标号

    1          条件分支语句 1.1       关系运算符 在C语言中0代表false,非0代表真 1.1.1          < 小于 1.1.2          <= 小于 ...

  8. Java中简单的操作(if语句、常用操作符、switch语句、变量赋值等)

    ---------------------if语句介绍--------------------------------------------------- class IfDemo { public ...

  9. python中修改函数内部的变量会发生什么

    最近写python遇到个函数内部变量使用外部变量的问题,现在总结下吧 #!/usr/bin/env python a = 100def su(): a = a + 1 print(a) s = su( ...

随机推荐

  1. asp.net c# 打开新页面或页面跳转

    1.最常用的页面跳转(原窗口被替代):Response.Redirect("XXX.aspx"); 2.利用url地址打开本地网页或互联网:Respose.Write(" ...

  2. poj2395 Out of Hay

    题意就是给你一张无向连通图,试问对于图上所有点对(u,v)从u到v的所有路径中边权最大值的最小值的最大值. 定义f(u,v)表示从u到v所有路径中边权最大值的最小值,对所有点对取其最大. 实际上就是求 ...

  3. 实现Fragment的切换和ViewPager自动循环设置切换时间

    1.FragmentActivity与Fragment之间的用法 2.实现ViewPager自动轮换,设置移动的时间 通过反射获取mScrooler这个对象: Field mScroller; mSc ...

  4. Unity Shader中自定义枚举类型

    效果 脚本: Properties { _MainTex ("Texture", 2D) = "white" {} [Enum(Enum1,,Enum2,)]_ ...

  5. 南阳oj 求N!的二进制表示最低位的1的位置(从右向左数)。

    N! 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 阶乘(Factorial)是一个很有意思的函数,但是不少人都比较怕它.现在这里有一个问题,给定一个N(0< ...

  6. CSocket服务器(TCP)

    我的理解:把服务器和客户端的交互工程比喻成外来人员访问公司,每来一个客户端访问,需要服务器的前台经理接待此客户,然后前台经理呼叫一个接待员来将客户带上楼.服务器的两个角色前台经理和接待员就是服务器的两 ...

  7. Page_Load 事件

    Page_Load 事件是众多 ASP.NET 可理解的事件之一.Page_Load 事件会在页面加载时被触发,然后 ASP.NET 会自动调用子例程 Page_Load<%@ Page Lan ...

  8. CodeForces 12C Fruits

    Fruits Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  9. 机器学习——SVM详解(标准形式,对偶形式,Kernel及Soft Margin)

    (写在前面:机器学习入行快2年了,多多少少用过一些算法,但由于敲公式太过浪费时间,所以一直搁置了开一个机器学习系列的博客.但是现在毕竟是电子化的时代,也不可能每时每刻都带着自己的记事本.如果可以掏出手 ...

  10. ZOJ 3819 Average Score(平均分)

    Description 题目描述 Bob is a freshman in Marjar University. He is clever and diligent. However, he is n ...