c 语言 switch 是多分支选择语句,专门用来对一个整型或者字符型表达式做等值匹配判断,和 if else if 链式结构功能相似,但是 switch 是根据表达式的值直接跳转到对应的 case 分支,执行效率更高,代码结构更加清晰,适合分支数量多并且是等值判断的场景。switch 括号里面的表达式结果必须是整型兼容类型,也就是 int char short long 这类,不能是浮点数也不能是字符串,每个 case 后面跟一个常量值,匹配成功就进入这个分支执行代码,分支里面的 break 关键字用来跳出 switch 结构,如果没有写 break,程序会继续向下穿透执行后面所有 case 的代码,这个穿透特性是 switch 最核心也最容易出错的特点,最后的 default 分支用来处理所有 case 都没有匹配成功的情况,相当于兜底分支,可以写也可以省略,理解跳转表这个底层原理之后,就能明白 switch 为什么适合固定常量等值判断,它底层很多编译器会生成跳转表,相比连续多次 if 比较,分支数量多的时候性能优势会体现出来,同时也要记住它的限制,不能做区间判断,这一点和 if else if 有本质区别。
基础语法结构
switch 后面紧跟英文小括号,括号内填写待判断表达式,后面是大括号包裹所有 case 和 default 分支,每一个 case 后面写常量加冒号,分支代码写在冒号后面,需要结束分支就添加 break,default 写在所有 case 末尾作为兜底。
基础标准写法
switch (表达式)
{
case 常量 1:
执行代码
break;
case 常量 2:
执行代码
break;
default:
兜底代码
break;
}
各组成部分深度说明
| 组成部分 | 说明 | 限制要点 |
|---|---|---|
| switch 括号表达式 | 待判断的值 | 只支持整型兼容类型,不支持 float double 字符串 |
| case 标签 | 匹配的常量 | 必须是编译期常量,不能是变量,同一个 switch 里面 case 常量不能重复 |
| break | 跳出当前 switch | 可以省略,省略之后发生 case 穿透 |
| default | 兜底分支 | 位置可以放在任意位置,不是必须写在最后 |
执行流程详细讲解
程序运行进入 switch 之后,首先计算括号里面表达式的数值,然后拿这个数值依次和每一个 case 后面的常量做等值比对,如果找到相等的 case,就从这个 case 位置开始往下执行代码。如果遇到 break,立刻跳出整个 switch,继续执行 switch 外面后续代码。如果没有 break,就继续执行下一个 case 里面的代码,不管下一个 case 常量是否匹配,这个现象就是 case 穿透。如果所有 case 全部比对都没有匹配成功,就进入 default 分支执行代码,default 执行完之后同样可以搭配 break 跳出 switch。
case 穿透不是错误,它是 switch 设计自带特性,很多场景会主动利用穿透,比如多个不同 case 值想要执行同一段代码,就可以把多个 case 写在一起,共用后面的代码块,不需要重复写代码。但是绝大多数新手是忘记写 break,意外发生穿透,造成逻辑错误,这个是高频 bug 来源。
完整示例代码
基础匹配示例
include
int main ()
{
int num = 2;
switch (num)
{
case 1:
printf ("选中 1");
break;
case 2:
printf ("选中 2");
break;
case 3:
printf ("选中 3");
break;
default:
printf ("没有匹配项");
break;
}
return 0;
}
主动利用 case 穿透示例
include
int main ()
{
int day = 1;
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf ("工作日");
break;
case 6:
case 7:
printf ("周末");
break;
}
return 0;
}
常见易错点汇总
| 错误类型 | 错误描述 | 修正方式 |
|---|---|---|
| 表达式类型错误 | switch 里面写浮点数或者字符串判断 | 改用 if else if,switch 只支持整型等值判断 |
| case 写变量 | case 后面使用变量作为标签 | case 标签必须是常量,不能是动态变量 |
| case 常量重复 | 同一个 switch 里面两个 case 数值一样,编译报错 | 保证所有 case 常量唯一 |
| 忘记 break | 意外穿透执行后面分支代码 | 不需要穿透就每个分支末尾加上 break |
| default 位置误解 | 认为 default 必须放在最后 | default 可以放在任意位置,但是推荐写在末尾可读性更好 |
| case 后面没有冒号 | case 常量后面漏掉冒号,语法报错 | case 常量后面必须添加冒号 |
拓展补充
switch 和 if else if 可以实现部分相同功能,但是两者适用场景不一样,switch 只能等值匹配,if else if 可以写大于小于区间判断,当判断条件是连续区间的时候,不能使用 switch,只能选择 if else if。C99 标准之后,switch 里面 case 标签可以定义局部变量,但是跨 case 定义变量要加大括号,避免变量作用域混乱。switch 嵌套也是合法写法,也就是 switch 分支内部再写一个 switch,嵌套之后 break 只会跳出离它最近的那一层 switch,不会一次性跳出外层 switch,这个在多层分支逻辑里面很容易混淆。编译器优化的时候,如果 case 数值比较密集,会生成跳转表,分支数量越多,相比 if else if 的性能优势越明显,如果 case 数值非常稀疏,编译器有可能退化成类似 if 比较的逻辑,性能优势就会消失。
【常见问题】
问题 1 c 语言 switch 为什么不能判断浮点数
回答 1 c 语言 switch 要求括号表达式必须是整型兼容类型,浮点数存在精度误差,标准语法不支持把 float 或者 double 放在 c 语言 switch 括号里面,如果需要浮点数多分支判断,需要改用 if else if 结构,不能继续使用 c 语言 switch。
问题 2 c 语言 switch 里面不写 break 会怎么样
回答 1 c 语言 switch 里面省略 break 就会触发 case 穿透,匹配成功的分支执行完成之后,不会跳出 switch,继续向下执行后续所有 case 代码,c 语言 switch 这个特性可以主动利用,但是忘记写 break 就会产生逻辑错误。
问题 3 c 语言 switch 里面 default 分支可以省略吗
回答 1 c 语言 switch 的 default 属于可选分支,不是强制要求,如果所有 case 都已经覆盖全部可能取值,可以不写 default,但是推荐保留 default 做异常兜底,提升 c 语言 switch 代码健壮性。
问题 4 c 语言 switch 的 case 后面可以写变量吗
回答 1 c 语言 switch 的 case 标签必须是编译期常量,不能使用动态变量,如果 case 后面写变量,编译器会直接报错,这是 c 语言 switch 语法硬性规定,动态条件判断要改用 if 语句实现。
【免责申明】
本文内容仅作为 c 语言 switch 相关知识学习参考,不同编译器对 switch 跳转表优化策略存在差异,代码示例适配常规 gcc 和 vc 环境,实际工程项目请遵循项目编码规范,本文不保证所有特殊编译场景完全适配,学习使用产生的相关问题由使用者自行承担。


