【C/C++】 switch-case 详解/全面总结
文章目录
- 【C/C++】 switch-case 详解/全面总结
- I – 基础概述
- 1.1 – 基础结构
- 1.2 – 使用举例
- II – 注意事项
- 2.1 – switch 语句中的表达式必须为整型
- 2.2 – 满足条件的 case 标签后的语句都会执行,直到 break 语句
- 2.3 – default 标签可以置于任何位置
- 2.4 – 标签使用的整型表达式必须为常量
- 2.5 – case 之前的语句永远不会执行
- 2.6 – case 标签不可以使用重复的值
- III – 特殊用法
- 3.1 – case 设置范围
- 3.2 – switch 初始化语句
- 3.3 – switch-case 符合语法的简易结构
- IV – 与 if else if 的比较
- V – 参考链接
I – 基础概述
类似 if-else
语句,switch-case
语句用于处理复杂的条件判断和分支操作,但相较前者有更好的可读性,在代码中出现冗长的 if-else
阶梯代码时,switch-case
语句可作为一个不错的替代方案。
1.1 – 基础结构
一个 switch 语句可以包含任意数量的 case 标签,每个 case 标签中可执行若干条语句,通常以 break 语句结束。default 标签为可选项,至多包含一个,用于处理 case 标签未列举的值。
switch (expression){case constant_expression_1 :// statement_1break;case constant_expression_2 :// statement_2break;/* ... */default:// statement_defaultbreak;}
switch 语句根据 expression (表达式) 的值,跳转到值对应的 case 标签,执行标签中包含的语句或语句块。
1.2 – 使用举例
#include int main(int argc, char* argv[]){const int x = 2;switch (x){case 1: std::cout << "x equals 1" << std::endl;break;case 2: std::cout << "x equals 2" << std::endl;break;case 3: std::cout << "x equals 3" << std::endl;break;default:std::cout << "x is other than 1, 2 and 3" << std::endl;break;}return 0;}
输出:
x equals 2
switch
根据 x 的值,跳转到匹配的 case
,执行其中的语句,此处为 2 ,遇到 break
结束。
II – 注意事项
2.1 – switch 语句中的表达式必须为整型
switch 语句中使用的表达式必须是整型 (int, char, enum) 表达式,不允许为其他类型。
// float type is not allowed in switch expressionfloat x = 1.1;switch (x){case 1.1: printf("case 1.1"); break;default: printf("default"); break;}
MSVC 编译器的报错为:
error C2450: switch expression of type 'float' is illegalnote: Integral expression required
switch 表达式类型 float 非法,要求整型表达式。
Java 中的 switch-case 语句中允许字符串类型。
2.2 – 满足条件的 case 标签后的语句都会执行,直到 break 语句
表达式值对应的 case
标签后的语句都会执行,直到遇到 break
语句,或者 switch 结束。标签结尾如果没有使用 break
则会 fall-through (“穿透”)。
示例:
const int x = 2;switch (x){case 1: std::cout << "x equals 1" << std::endl;case 2: std::cout << "x equals 2" << std::endl;case 3: std::cout << "x equals 3" << std::endl;[[fallthrough]];default : std::cout << "x is other than 1, 2 and 3" << std::endl;break;}
输出:
x equals 2x equals 3x is other than 1, 2 and 3
注:[[fallthrough]] 为 C++17 引入的属性,用于禁止编译器产生 fall-through 的 “穿透” 警告。
2.3 – default 标签可以置于任何位置
default 标签可以置于 switch 内的任何位置,无论位置先后,如果没有任何的 case 值匹配,则会执行 default 标签后的语句。
int x = 4;switch (x){default : std::cout << "x is other than 1, 2 and 3" << std::endl;break;case 1: std::cout << "x equals 1" << std::endl; break;case 2: std::cout << "x equals 2" << std::endl; break;}
输出
x is other than 1, 2 and 3
结合前一小节,default 标签中无 break 语句,也会穿透,直到 break 为止,示例:
int x = 4;switch (x){default : std::cout << "x is other than 1, 2 and 3" << std::endl;case 1: std::cout << "x equals 1" << std::endl;break;case 2: std::cout << "x equals 2" << std::endl;}
此处打印为:
x is other than 1, 2 and 3x equals 1
由于 case 1 包含 break 语句,只“穿透”到 case 1。
2.4 – 标签使用的整型表达式必须为常量
case 标签使用的整型表达式必须是常量表达式。
// A program with variable expressions in labels#include int main(){int x = 2;int arr[] = {1, 2, 3};switch (x){case arr[0]: printf("Choice 1\n");case arr[1]: printf("Choice 2\n");case arr[2]: printf("Choice 3\n");}return 0;}
编译报错为:
error C2131: expression did not evaluate to a constantnote: failure was caused by a read of a variable outside its lifetimenote: see usage of 'arr'error C2051: case expression not constant
case 表达式不为常量
2.5 – case 之前的语句永远不会执行
在 switch 语句后,控制语句跳转到匹配的 case 标签,写在 case 标签前的语句不会被执行。
示例:
// statement before all cases are never executedint x = 2;switch (x){x = x + 1; // 此条语句不会执行, this statement is not executedcase 1: std::cout << "x equals 1" << std::endl; break;case 2: std::cout << "x equals 2" << std::endl; break;case 3: std::cout << "x equals 3" << std::endl; break;default : std::cout << "x is other than 1, 2 and 3" << std::endl;break;}
此时输出为
x equals 2
而不是 x equals 3
,由于语句 x = x + 1
不会执行。
2.6 – case 标签不可以使用重复的值
// duplicate case valueint x = 2;switch (x){case 1+1: std::cout << "x equals 1" << std::endl; break;case 2: std::cout << "x equals 2" << std::endl; break;case 3: std::cout << "x equals 3" << std::endl; break;default : std::cout << "x is other than 1, 2 and 3" << std::endl;break;}
编译报错为:
error C2196: case value '2' already used
case 标签值 ‘2’ 已使用。
III – 特殊用法
3.1 – case 设置范围
可在单个 case
标签指定一个连续的数值范围,低值在前,高值在后。
case low ... high:
...
左右两边需要有一个空格
case 1 ... 5: // correctcase 1...5: // wrong
除可以使用整数外,还可以使用如字符型常量。
case 'A' ... 'Z':
使用举例:
#include int main(int argc, char* argv[]) { int data[10] = { 5, 4, 10, 25, 60, 47, 23, 80, 14, 11}; int i; for (i = 0; i < 10; ++i) {switch (data[i]){ case 1 ... 10:printf("%d 在范围 1 - 10 之间\n", data[i]); break; case 11 ... 20:printf("%d 在范围 11 - 20 之间\n", data[i]); break; case 21 ... 30:printf("%d 在范围 21 - 30 之间\n", data[i]); break; case 31 ... 40:printf("%d 在范围 31 - 40 之间\n", data[i]); break; default:printf("%d 超出范围\n", data[i]); break;} }}
输出
5 在范围 1 - 10 之间4 在范围 1 - 10 之间10 在范围 1 - 10 之间25 在范围 21 - 30 之间60 超出范围47 超出范围23 在范围21 - 30 之间80 超出范围14 在范围 11 - 20 之间11 在范围 11 - 20 之间
查看 gcc 官网的描述 :
https://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC82
注:
- 仅 GCC 支持, Visual Studio 的 MSVC 编译器当前不支持。
3.2 – switch 初始化语句
C++17 标准引入新特性,switch 语句中允许初始化语句。
switch (init-statement; expression){case constant_expression: statement; break;/* ... */}// 等价于{init-statement;switch (expression){case constant_expression: statement; break;/* ... */}}
使用示例:
struct RemoteDevice{enum State { SLEEP, READY, ERROR };auto state() const { return m_state; }/*...*/private:State m_state{};};switch (auto rmt = RemoteDevice{}; rmt.state()){case RemoteDevice::SLEEP:/*...*/break;case RemoteDevice::READY:/*...*/break;case RemoteDevice::ERROR:/*...*/break;}
3.3 – switch-case 符合语法的简易结构
switch 语句可以不为完整的复合结构,示例:
// 此条不做任何事switch (0)std::cout << "this doses nothing\n";switch (int n = 1){case 0:case 1:std::cout << n << '\n';}
同 if / while 等语句,switch 语句无大括号时,可紧跟一个标签以及一条语句。
// 此条总是打印switch (0)default:std::cout << "this print always\n";
IV – 与 if else if 的比较
switch | if else if |
---|---|
执行不同的 case 基于 switch 中的变量值 | 执行不同的代码块,基于指定的条件判断 |
仅可执行整型表达式 (int, char, enum) | 可执行任意类型的表达式 |
在较多的条件判断时,更快且具有更好的可读性 | 当有很多条件时,它会变得混乱。 |
不支持逻辑表达式判断 | 可支持逻辑表达式,以及范围的判断 |
- 编译不同:
当编译器编译 switch 语句时,它将检查每个 case 常量并创建一个“跳转表”,该表将用于根据表达式的值选择执行路径。因此,如果我们需要在一大组值中进行选择,switch 语句的运行速度将比使用 if-else 序列编码的等效逻辑快得多。编译器可以这样做,因为它知道 case 常量都是相同的类型,并且必须与 switch 表达式进行比较以相等,而在 if 表达式的情况下,编译器没有这样的认知。
- 速度基于条件数量:
switch 语句比 if else if 更快的前提是条件足够多。如果只有少数判断,则可能不会影响速度。如过条件数超过 5 个,则首选 switch-case
,否则也可以使用 if-else
。
如果 switch 包含五个以上的条件,则使用查找表 (lookup table) 或哈希链 (hash list) 实现。这意味着所有条件获得相同的访问时间,而在 if else if 列表中,最后一个条件需要更多时间才能到达,因为它必须首先评估之前的每个条件。
V – 参考链接
- Cpp Reference
- https://en.cppreference.com/w/cpp/language/switch
- https://en.cppreference.com/w/c/language/switch