命名空间
变体
操作

switch 语句

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
 
 

根据条件的值,将控制权转移到若干语句之一。

目录

[编辑] 语法

属性 (可选) switch ( init-statement (可选) 条件 ) 语句
属性 - (自 C++11 起) 任意数量的属性
init-statement - (自 C++17 起) 以下任何一种
(C++23 起)

注意,任何 init-statement 都必须以分号结尾。这就是为什么它通常被非正式地描述为表达式或声明后跟分号的原因。

条件 - 一个条件
语句 - 一个语句(通常是复合语句)

[编辑] 条件

条件可以是一个表达式或一个简单声明

  • 如果它在语法上可以解析为结构化绑定声明,则将其解释为结构化绑定声明。
(C++26 起)
  • 如果它在语法上可以解析为表达式,则将其视为表达式。否则,将其视为非结构化绑定声明(自 C++26 起)

当控制到达条件时,条件将产生一个值,该值用于确定控制将转到哪个标签。

[编辑] 表达式

如果 条件 是一个表达式,则它产生的值就是表达式的值。

[编辑] 声明

如果 条件 是一个简单声明,则它产生的值是决策变量(见下文)的值。

[编辑] 非结构化绑定声明

该声明有以下限制:

  • 语法上符合以下形式:
  • type-specifier-seq declarator = assignment-expression
(C++11 前)
  • attribute-specifier-seq(可选) decl-specifier-seq declarator brace-or-equal-initializer
(C++11 起)

声明的决策变量是被声明的变量。

结构化绑定声明

该声明有以下限制:

声明的决策变量是由声明引入的假定变量 e

(C++26 起)

[编辑] 类型

条件只能产生以下类型:

  • 整型
  • 枚举类型
  • 类类型

如果产生的值是类类型,它会隐式地上下文转换为整型或枚举类型。

如果(可能转换后的)类型受整型提升影响,则产生的值会被转换为提升后的类型。

[编辑] 标签

switch 语句内的任何语句都可以带有一个或多个以下标签:

属性 (可选) case 常量表达式 : (1)
属性 (可选) default: (2)
属性 - (自 C++11 起) 任意数量的属性
常量表达式 - 一个转换后的常量表达式,其类型为 switch 条件的调整类型。


一个 casedefault 标签与包含它的最内层 switch 语句相关联。

如果满足以下任何条件,程序将不正确:

  • 一个 switch 语句关联了多个 case 标签,其 常量表达式 在转换后具有相同的值。
  • 一个 switch 语句关联了多个 default 标签。

[编辑] 控制流转移

switch 语句的条件产生一个(可能已转换的)值时:

  • 如果其中一个关联的 case 标签常量具有相同的值,则控制权将传递给由匹配的 case 标签标记的语句。
  • 否则,如果存在关联的 default 标签,则控制权将传递给由 default 标签标记的语句。
  • 否则,switch 语句中的任何语句都不会被执行。

casedefault 标签本身不会改变控制流。要从 switch 语句中途退出,请参阅break 语句

编译器可能会对贯穿(在没有 break 的情况下到达下一个 casedefault 标签)发出警告,除非属性 [[fallthrough]] 紧接在 case 标签之前出现,表示此贯穿是故意的(自 C++17 起)

switch (1)
{
    case 1:
        std::cout << '1'; // prints "1",
    case 2:
        std::cout << '2'; // then prints "2"
}
switch (1)
{
    case 1:
        std::cout << '1'; // prints "1"
        break;            // and exits the switch
    case 2:
        std::cout << '2';
        break;
}

带初始化器的 switch 语句

如果使用 init-statement,则 switch 语句等价于

{
init-statement
switch ( 条件 ) 语句

}

除了由 init-statement 声明的名称(如果 init-statement 是声明)和由 条件 声明的名称(如果 条件 是声明)位于同一作用域,该作用域也是 语句 的作用域。

(C++17 起)

[编辑] 注意

由于不允许控制权进入变量的作用域,如果在 语句 内部遇到声明语句,则必须将其置于其自己的复合语句中。

switch (1)
{
    case 1:
        int x = 0; // initialization
        std::cout << x << '\n';
        break;
    default:
        // compilation error: jump to default:
        // would enter the scope of 'x' without initializing it
        std::cout << "default\n";
        break;
}
switch (1)
{
    case 1:
        {
            int x = 0;
            std::cout << x << '\n';
            break;
        } // scope of 'x' ends here
    default:
        std::cout << "default\n"; // no error
        break;
}

[编辑] 关键词

switch, case, default

[编辑] 示例

以下代码展示了 switch 语句的几种用法:

#include <iostream>
 
int main()
{
    const int i = 2;
    switch (i)
    {
        case 1:
            std::cout << '1';
        case 2:              // execution starts at this case label
            std::cout << '2';
        case 3:
            std::cout << '3';
            [[fallthrough]]; // C++17 attribute to silent the warning on fallthrough
        case 5:
            std::cout << "45";
            break;           // execution of subsequent statements is terminated
        case 6:
            std::cout << '6';
    }
 
    std::cout << '\n';
 
    switch (i)
    {
        case 4:
            std::cout << 'a';
        default:
            std::cout << 'd'; // there are no applicable constant expressions 
                              // therefore default is executed
    }
 
    std::cout << '\n';
 
    switch (i)
    {
        case 4:
            std::cout << 'a'; // nothing is executed
    }
 
    // when enumerations are used in a switch statement, many compilers
    // issue warnings if one of the enumerators is not handled
    enum color { RED, GREEN, BLUE };
    switch (RED)
    {
        case RED:
            std::cout << "red\n";
            break;
        case GREEN:
            std::cout << "green\n";
            break;
        case BLUE:
            std::cout << "blue\n";
            break;
    }
 
    // the C++17 init-statement syntax can be helpful when there is
    // no implicit conversion to integral or enumeration type
    struct Device
    {
        enum State { SLEEP, READY, BAD };
        auto state() const { return m_state; }
 
        /* ... */
 
    private:
        State m_state{};
    };
 
    switch (auto dev = Device{}; dev.state())
    {
        case Device::SLEEP:
            /* ... */
            break;
        case Device::READY:
            /* ... */
            break;
        case Device::BAD:
            /* ... */
            break;
    }
 
    // pathological examples
 
    // the statement does not have to be a compound statement
    switch (0)
        std::cout << "this does nothing\n";
 
    // labels do not require a compound statement either
    switch (int n = 1)
        case 0:
        case 1:
            std::cout << n << '\n';
}

输出

2345
d
red
1

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确的行为
CWG 1767 C++98 条件 的类型不受
整型提升
不提升
条件 的这些类型
CWG 2629 C++98 条件 可以是浮点变量的声明 已禁止

[编辑] 另请参阅

C 文档 关于 switch

[编辑] 外部链接

1.  使用 Duff's Device 的循环展开
2.  Duff's device 可用于在 C/C++ 中实现协程