【C/C++】switch-case 使用全面总结

news/2025/1/8 20:46:16/

【C/C++】switch-case 使用全面总结

文章目录

  • 【C/C++】switch-case 使用全面总结
    • I - 基础概述
      • 1.1 - 基础结构
      • 1.2 - 使用举例
      • 1.3 - 注意事项
        • 1.3.1 - switch 语句中的表达式必须是整型
        • 1.3.2 - 满足条件的 case 标签后的语句都会执行,直到 break 语句
        • 1.3.3 - default 标签可以置于任何位置
        • 1.3.4 - 标签使用的整型表达式必须是常量表达式
        • 1.3.5 - case 之前的语句永远不会执行
        • 1.3.6 - case 标签不可以使用重复的值
    • II - 特殊用法
      • 2.1 - case 后跟范围
      • 2.2 - switch 中初始化语句
      • 2.3 - switch - case 不必为完整的复合结构
    • III - 分析
      • 3.1 - 与 if else if 的比较
    • 参考链接

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 <iostream>
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

1.3 - 注意事项

1.3.1 - switch 语句中的表达式必须是整型


switch 语句中使用的表达式必须是整型 (int, char, enum) ,表达式不允许为其他类型。

// float type is not allowed in switch expression
float 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 illegal
note: Integral expression required

switch 表达式类型 float 非法,要求整型表达式。

Java 中的 switch-case 语句中允许字符串类型。

1.3.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 2
x equals 3
x is other than 1, 2 and 3

注:[[fallthrough]] 为 C++17 引入的属性,用于禁止编译器产生 fall-through 的 “穿透” 警告。

1.3.3 - default 标签可以置于任何位置


default 标签可以置于 switch 内的任何位置,无论位置先后,如果没有任何的 case 值匹配上,它仍会执行。

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 3
x equals 1

1.3.4 - 标签使用的整型表达式必须是常量表达式


// A program with variable expressions in labels
#include <stdio.h>
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 constant
note: failure was caused by a read of a variable outside its lifetime
note: see usage of 'arr'
error C2051: case expression not constant

case 表达式不为常量

1.3.5 - case 之前的语句永远不会执行


在 switch 语句后,控制语句跳转到匹配的 case 标签,写在 case 标签前的语句不会被执行。

示例:

// statement before all cases are never executed
int 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;
}

1.3.6 - case 标签不可以使用重复的值


// duplicate case value
int 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

此时输出为

x equals 2

而不是,x equals 3 。因为 x = x + 1 不会执行。

II - 特殊用法

2.1 - case 后跟范围


可在单个 case 标签指定一个连续的数值范围,低值在前,高值在后。

case low ... high:

... 左右两边需要有一个空格

case 1 ... 5: // correct
case 1...5: // wrong 

除可以使用整数外,还可以使用如字符型常量。

case 'A' ... 'Z':

使用举例:

#include <stdio.h>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 编译器当前不支持。

2.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;
}

2.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";

III - 分析

3.1 - 与 if else if 的比较


switchif else if
执行不同的 case 基于 switch 中的变量值执行不同的代码块,基于指定的条件判断
仅可执行整型表达式 (int, char, enum)可执行任意类型的表达式
在较多的条件判断时,更快且具有更好的可读性当有很多条件时,它会变得混乱。
不支持逻辑表达式判断可支持逻辑表达式,以及范围的判断
  • 编译不同

当编译器编译 switch 语句时,它将检查每个 case 常量并创建一个“跳转表”,该表将用于根据表达式的值选择执行路径。因此,如果我们需要在一大组值中进行选择,switch 语句的运行速度将比使用 if-else 序列编码的等效逻辑快得多。编译器可以这样做,因为它知道 case 常量都是相同的类型,并且必须与 switch 表达式进行比较以相等,而在 if 表达式的情况下,编译器没有这样的知识。

  • 速度基于条件数量

switch 语句比 if else if 更快的前提是条件足够多数良好。如果只有少数判断,则可能不会影响速度。如过条件数超过 5 个,则首选switch ,否则也可以使用 if-else。

如果 switch 包含五个以上的条件,则使用查找表 (lookup table) 或哈希链 (hash list) 实现。这意味着所有条件获得相同的访问时间,而在 if else if 列表中,最后一个条件需要更多时间才能到达,因为它必须首先评估之前的每个条件。

参考链接

  • Cpp Reference
    • https://en.cppreference.com/w/cpp/language/switch
    • https://en.cppreference.com/w/c/language/switch

http://www.ppmy.cn/news/464024.html

相关文章

FFmpeg学习(四)-- libavformat 代码组成

libavformat 代码组成 libavformat库中包含了ffmpeg支持的protocol、muxer、demuxer算法&#xff0c;提供了一些可以在所有muxer和demuxer上设置的通用全局选项。 此外&#xff0c;每个muxer或demuxer可能支持基于特定组件的私有选项。libavformat使用CONFIG_name_type(MUXER、…

华为操作系统 28 年史

作者 | 老兵戴辉 本文经授权转自公众号最牛博弈&#xff08;ID&#xff1a;zngame&#xff09; 8月9日&#xff0c;东莞松山湖沸腾的一天&#xff0c;华为消费者业务CEO余承东发布了鸿蒙操作系统&#xff0c;中文来自山海经&#xff0c;英文叫HarmonyOS&#xff0c;不是以前传…

为什么需要Linux?

0.1 为什么需要Linux&#xff1f; 如果你真的喜欢计算机&#xff0c;Linux绝对是你梦想中的操作系统。它比现在所有其他的操作系统更加有意思。然而&#xff0c;Linux的真正革命在于它是开放的软件。我们在科技和技术方面的发展为今日的免费信息和相互检查提供了可能性。 举个…

Linux 相关问答

0.1 为什么需要Linux&#xff1f; 如果你真的喜欢计算机&#xff0c; Linux绝对是你梦想中的操作系统。它比现在所有其他的操作系统更加有意思。然而&#xff0c;Linux的真正革命在于它是开放的软件。我们在科技和技术方面的发展为今日的免费信息和相互检查提供了可…

云游戏能成为5G第一个杀手级应用吗?

5G低延迟、大带宽、海量连接的特性与AI技术的进一步成熟&#xff0c;将为消费电子应用注入新动能。其中&#xff0c;我们认为AR/VR与云游戏&#xff08;Cloud gaming&#xff09;是消费电子应用中主要受益的两大方向。 云游戏与AR/VR等新一代智能硬件结合&#xff0c;可能成为5…

从0开始学架构总结

从0开始学架构总结 架构设计三原则合适原则简单原则演化原则小结&#xff1a; 架构设计流程&#xff1a;识别复杂度如何识别复杂度小结 架构设计流程&#xff1a;设计备选方案第一种常见的错误&#xff1a;设计最优秀的方案第二种常见的错误&#xff1a;只做一个方案小结 架构设…

云计算原理与实践

基于《云计算原理与实践》 文章目录 云计算概述云计算定义云计算的计算模式演讲过程云计算的优势云计算的缺点云计算的推动力云计算的公共特征云计算的分类与云计算相关的技术耦合数据中心云计算面临的挑战大数据 云计算架构云计算的本质云计算的基石云数据中心云的工作负载模…

k8s-/var/lib/docker 目录下无用资源清除

在 /var/lib/docker 目录下&#xff0c;有一些常见的子目录&#xff1a; aufs、overlay2、vfs 用于存储镜像文件和容器文件。containers, image, network, 和 volumes 子目录&#xff0c;存储 Docker 使用的元数据。 使用以下命令可查找 /var/lib/docker 目录下未被使用的文件…