C switch-case 分支
更新时间:2026-08-26。本文是
languages/c/主题入门层第 14 篇。if-else 处理"是/否",switch 处理"多选一"。它看着简单,但 C 的 switch 有个反直觉的**穿透(fall-through)**行为,是 bug 高发点。
本文要回答的问题
- switch 和 if-else 链什么区别?什么时候用 switch?
- 忘写
break会发生什么? - case 为什么必须是整型常量?
一、基本语法
c
int cmd;
scanf("%d", &cmd);
switch (cmd) {
case 1:
printf("查询\n");
break;
case 2:
printf("新增\n");
break;
case 3:
case 4: // case 3 和 4 共享同一段代码
printf("修改或删除\n");
break;
default:
printf("未知命令\n");
break;
}规则:
switch括号里是整型表达式(int、char、枚举);case后面必须是编译期可确定的整型常量(字面量、const不行的宏或枚举)——不能是变量;default处理所有没列出的值,可放任意位置(惯例放最后);- 每个 case 后面通常要
break,否则穿透。
二、fall-through:穿透
c
int x = 2;
switch (x) {
case 1: printf("一");
case 2: printf("二"); // 匹配到这里
case 3: printf("三"); // 没有 break,继续往下!
default: printf("默认");
}
// 输出:二三默认case 不是"独立的块",而是"跳转的入口"。匹配到 case 2 后,从那里开始往下执行,直到遇到 break 或 switch 结束。忘写 break 是最常见的 switch bug。
不过穿透有时是特性:多个 case 共享代码(上面例子的 case 3: case 4:)、或者故意做"分级处理"(case 1: 处理一部分,故意掉进 case 2: 补全)。想用穿透时,加注释 /* fall through */,让读者知道你是故意的。
三、case 里的变量声明
case 后面直接声明变量会报错(跨 case 跳转导致初始化被跳过),需要用花括号包起来:
c
switch (x) {
case 1: {
int local = 10; // 花括号限定作用域
printf("%d\n", local);
break;
}
default:
break;
}C23 之后允许直接声明,但多数编译器还是 C17 及以下——用花括号包,最保险。
四、switch vs if-else:怎么选
| 场景 | 推荐 | 原因 |
|---|---|---|
| 值域小且连续(1~10) | switch | 可编译成跳转表(O(1)),比 if-else 链快 |
| 值域大 / 不连续 | if-else | case 太多跳转表不划算 |
| 条件复杂(范围、逻辑组合) | if-else | switch 只支持相等匹配 |
| 字符串匹配 | if-else | switch 不能匹配字符串 |
跳转表是 switch 的性能红利:连续的小整数 case,编译器生成一张"地址表",直接跳过去,不用逐个比较。这也就是为什么 switch 比等价的 if-else 链快——细节见编译优化行为。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
忘写 break | 执行了后面的 case | 每个 case 检查 break |
| case 用变量 | 编译错误 | case 只能是常量 |
| 用字符串做 case | 编译错误 | 改用 if-else |
| 穿透没注释 | 读者以为是 bug | 故意穿透加注释 |
| case 里声明变量 | 编译错误 | 用花括号包 |
六、与本站主线衔接
一句话总结
switch 匹配整型常量、每个 case 记得 break(故意的穿透要注释)、default 兜底、case 声明变量用花括号包;连续小整数多选一用 switch(编译器生成跳转表),复杂条件用 if-else。