Switch-case 内定义变量的问题

本博客为转载作者如下:
严正声明:
作者:psklf
出处: https://www.cnblogs.com/psklf/p/6702767.html
欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任!
Switch-case 内定义变量的问题

这个问题需要分开讨论,C 语言和 C++ 的标准定义是不同的。
C++

int Caset(int a) {
switch (a) {
case 1:
int b = 1;
std::cout<<"a1: "<<b<<std::endl;
break;
case 2:
b = 2;
std::cout<<"a
2: "<<b<<std::endl;
break;
}
}

编译报错信息为

simple.cc:35:9: error: cannot jump from switch statement to this case label
case 2:
^
simple.cc:32:17: note: jump bypasses variable initialization
int b = 1;
^

也就是说,跳到 case2 的这个地方,忽略了对于 b 这个变量的初始化,这个很直观,就是在这里我找不到 b。

那么如果改成

int Caset(int a) {
switch (a) {
case 1:
int b;
b = 1;
std::cout<<"a1: "<<b<<std::endl;
break;
case 2:
b = 2;
std::cout<<"a
2: "<<b<<std::endl;
break;
}
}

顺利成功,没有报错,如果 a 为 2,那么输出 b 也是 2,说明逻辑没有问题。那么问题来了,b 在前面声明,为什么后面可以用到呢,因为 switch-case 的逻辑控制就是用 label 来标记跳转的,而不是别的复杂的逻辑控制,所以 b 的作用域是在整个 switch 的花括号内,关于这个问题见知乎讨论请教switch内部的变量定义问题。
C 语言

上面两种写法统统出错,

void Caset(int a) {
switch (a) {
case 1:
/* one style */
int b;
b = 1;

        /* another style */
        int b = 1;

        printf("1: %d", b);
        break;
    case 2:
        b = 2;
        printf("2: %d", b);
        break;
}

}

两种写法都错

First style:

main.c:12:13: error: expected expression
int b;
^
main.c:13:13: error: use of undeclared identifier ‘b’
b = 1;
^

Another style:

ttt.c:11:13: error: expected expression
int b = 1;
^

意思是说,此处需要一个表达式(expression),而不是一个变量声明初始化。有一个很黑客的做法,如下:

void Caset(int a) {
switch (a) {
case 1:
;
int b = 1;
// b = 1;

        printf("1: %d \n", b);
        break;
    case 2:
        b = 2;
        printf("2: %d \n", b);
        break;
}

}

这个很不能理解了,其实也就是说保证 case 后面跟着的确实是 expression 即可。考虑一下 C++ 代码出现的问题:跳过变量的声明?C 语言中同样跳过,但是编译器不认为这个是错误,而且逻辑上面也是没有问题的,在后面的 case 中可以正常给变量赋值,但是如果 case2 中,我不是给 b 赋值,而是直接访问 b,那返回的数值就是一个随机的错误的数据了,我在我的电脑上使用 gcc 编译,若直接读取数据,得到的是 0,当然编译通过,连警告都没有。

总结起来就是:

C 编译器允许一个 case 使用另一个 case 后声明定义的变量,但是 C++ 语法不允许这个
C 不允许 case 后面紧跟声明或定义,只允许表达式(expression); C++ 对这个没有限制

通用解法

当然我认为这样的代码可读性差,比较好的做法可以是将声明变量的事情放在头上做。

void Caset(int a) {
switch (a) {
int b;
case 1:
b = 1;
// b = 1;
printf(“1: %d \n”, b);
break;
case 2:
b = 2;
printf(“2: %d \n”, b);
break;
}
}

但是要留心, switch 和 case 之前那块地方也就只能写写这样的声明,写别的表达式,赋值啊什么的,统统是不会生效的。
/以上为作者原文内容***/

/以下内容摘自知乎评论****/

题主知道这里的内存空间是分配在栈上的就好办了。为什么c语言要求函数里变量定义必须放在最开始呢,就是为了方便函数调用。在函数调用时会把当前代码地址,函数用到的参数按顺序压入栈(不同调用方式压入顺序不同,实际还要压入esp,把eip存入esp等,为了方便说明暂且忽略了),然后就是根据函数内部声明的变量所需要的空间一次性分配相应的栈内存,然后跳到函数的代码段执行。c++为了方便可以随时声明变量,但系统在函数调用时还是一次性分配所有函数变量所需空间。所以从这段代码来看,函数在开始执行之前就给那个变量分配了内存,通过变量名可以访问到对应内存的值,因为没有初始化,所以结果应该是随机的。
作者:durow
链接:https://www.zhihu.com/question/23051685/answer/23468222
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

变量的定义不是语句,所以无需执行也是全范围有效。
作者:pansz
来源:知乎

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值