C语言switch case语句中定义变量问题

本文详细探讨了C与C++中switch-case结构内的变量声明与作用域差异。通过具体示例展示了两种语言的不同行为,并解释了背后的原理。特别关注了变量初始化与作用域限制等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

严正声明:
作者:psklf
出处: http://www.cnblogs.com/psklf/p/6702767.html
欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任!

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

int Caset(int a) {
    switch (a) {
        case 1:
            int b = 1;
            std::cout<<"a==1: "<<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<<"a==1: "<<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;
    }
}

两种写法都错,报错信息:

main.c:12:13: error: expected expression
    int b; 
    ^
main.c:13:13: error: use of undeclared identifier 'b'
    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,当然编译通过,连警告都没有。

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

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语言 `switch`-`case` 语句概述 在C语言中,`switch`-`case` 是一种多分支选择结构,用于根据变量的不同取值来执行不同的操作。相比 `if...else` 结构,在处理多个固定值的条件判断时更为简洁和高效[^2]。 #### 基本语法格式 ```c switch (expression) { case constant-expression: statement(s); break; case constant-expression: statement(s); break; ... default: statement(s); } ``` 其中: - `expression` 表达式的计算结果应为整数型或字符型。 - 每个 `case` 后面跟的是常量表达式,当 `expression` 的值等于该常量表达式的值时,则执行对应的语句序列。 - 如果没有任何一个 `case` 符合条件,默认情况下会执行 `default` 部分的内容;如果存在匹配项且其后有 `break` 则不会进入默认部分。 - 关键字 `break` 起着终止当前 `case` 并退出整个 `switch` 语句的作用。如果没有设置 `break` ,程序将继续向下执行直到遇到第一个 `break` 或者到达 `switch` 体结束位置[^3]。 #### 实际应用案例分析 考虑如下一段代码片段展示了一个典型的 `switch`-`case` 使用场景: ```c #include <stdio.h> int main() { int num = 1; switch (num) { case 1: printf("Case 1\n"); // 缺少 break 导致穿透至下一条 case 分支 case 2: printf("Case 2\n"); case 3: printf("Case 3\n"); case 4: printf("Case 4\n"); break; // 此处设置了 break 来阻止进一步穿透 default: printf("Default Case\n"); } return 0; } ``` 上述例子展示了所谓的 “case 穿透” 效果:由于缺少 `break` 语句,一旦某个 `case` 成立之后便会一直往下执行直至遇见首个 `break` 。因此这段代码最终输出将是:“Case 1”,“Case 2”,“Case 3”,最后是“Case 4”。这正是通过省略某些地方的 `break` 达到了预期的效果[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值