switch() 语句

当你希望程序根据特定测试变量的值执行许多不同的操作时,switch 语句非常有用。

switch 语句的示例用法如下:

int a = 1;

switch (a) {
case 1:
    puts("a is 1");
    break;
case 2:
    puts("a is 2");
    break;
default:
    puts("a is neither 1 nor 2");
    break;
}

这个例子相当于

int a = 1;

if (a == 1) {
    puts("a is 1");
} else if (a == 2) {
    puts("a is 2");
} else {
    puts("a is neither 1 nor 2");
}

如果使用 switch 语句时 a 的值为 1,则将打印 a is 1。如果 a 的值是 2,那么将打印 a is 2。否则,将打印 a is neither 1 nor 2

case n:用于描述当传递给 switch 语句的值为 n 时执行流将跳入的位置。 n 必须是编译时常量,并且在一个 switch 语句中最多只能存在一次 n

default:用于描述当值与 case n:的任何选项都不匹配时。在每个 switch 语句中包含 default 案例以捕获意外行为是一种好习惯。

跳出 switch 区块需要一个 break; 声明。

注意: 如果你不小心忘记在 case 结束后添加 break,编译器将假定你打算 通过 并且将执行所有后续的 case 语句(如果有的话)(除非在中找到 break 语句)任何后续案例),无论后续 case 语句是否匹配。此特定属性用于实现 Duff 的设备 。这种行为通常被认为是 C 语言规范中的一个缺陷。

下面是一个显示没有 break; 的影响的例子:

int a = 1;

switch (a) {
case 1:
case 2:
    puts("a is 1 or 2");
case 3:
    puts("a is 1, 2 or 3");
    break;
default:
    puts("a is neither 1, 2 nor 3");
    break;
}

a 的值为 1 或 2 时,将打印 a is 1 or 2a is 1, 2 or 3。当 a 为 3 时,仅打印 a is 1, 2 or 3。否则,将打印 a is neither 1, 2 nor 3

请注意,default 的情况不是必需的,尤其是当你在 switch 中获得的值集完成并在编译时已知时。

最好的例子是在 enum 上使用 switch

enum msg_type { ACK, PING, ERROR };
void f(enum msg_type t)
{
  switch (t) {
  case ACK:
    // do nothing
    break;
  case PING:
    // do something
    break;
  case ERROR:
    // do something else
    break;
  }
}

这样做有很多好处:

  • 如果你没有处理一个值,大多数编译器都会报告一个警告(如果存在 default 案例则不会报告)
  • 出于同样的原因,如果你向 enum 添加一个新值,你会收到你忘记处理新值的所有地方的通知(使用 default 的情况,你需要手动探索你的代码搜索这样的情况)
  • 读者不需要弄清楚“default:隐藏了什么”,是否有其他的 enum 值或者它是否是以防万一的保护。如果还有其他的 enum 值,那么编码器是否有意为他们使用了 default 的情况,还是在添加值时引入了一个错误?
  • 处理每个 enum 值使代码自我解释,因为你不能隐藏在外卡后面,你必须明确地处理它们中的每一个。

然而,你不能阻止别人写下如下的邪恶代码:

enum msg_type t = (enum msg_type)666; // I'm evil

因此,如果你确实需要,可以在切换之前添加额外的检查以检测它。

void f(enum msg_type t)
{
   if (!is_msg_type_valid(t)) {
      // Handle this unlikely error
   }

   switch(t) { 
    // Same code than before
   }
}