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