switch文 - 整数の高速な条件分岐

switch文を使うと、整数の高速な条件分岐を行うことができます。

switch (値) {
  case ケース1の値:
    // 処理1
    break;
  case ケース2の値:
    // 処理2
    break;
  case ケース3の値:
    // 処理3
    break;
  default:
    // 上記以外のケースの場合の処理
}

break文は必須ではありませんが、breakがない場合は、switch文の外には移動せずに、下の文が実行されます。

switch (値) {
  case ケース1の値:
  case ケース2の値:
    // ケース1あるいはケース2の場合の処理
    break;
  case ケース3の値:
    // 処理3
    break;
  default:
    // 上記以外のケースの場合の処理
}

break文の記述のし忘れは、経験的に語ると、頻繁に発生します。「あれ、おかしいな、プログラムの動きが謎過ぎる」と思ったらbreak文書き忘れてたみたいな。

switch文のそれぞれの場合の処理では、変数宣言を行いたい場合も多いので、変数宣言を行いたい場合は、以下のようにスコープを作っておくとよいでしょう。

switch (値) {
  case ケース1の値: {
    // 処理1
    break;
  }
  case ケース2の値: {
    // 処理2
    break;
  }
  case ケース3の値: {
    // 処理3
    break;
  }
  default: {
    // 上記以外のケースの場合の処理
  }
}

switch文を使ったサンプルです。列挙型と組み合わせて使っています。

#include <stdint.h>
#include <stdio.h>

enum {
  SPVM_OP_C_ID_IF,
  SPVM_OP_C_ID_UNLESS,
  SPVM_OP_C_ID_ELSIF,
  SPVM_OP_C_ID_ELSE,
  SPVM_OP_C_ID_FOR,
};

int main(void) {
  
  int32_t id = SPVM_OP_C_ID_UNLESS;
  
  switch (id) {
    case SPVM_OP_C_ID_IF: {
      printf("IF\n");
      break;
    }
    case SPVM_OP_C_ID_UNLESS: {
      printf("UNLESS\n");
      break;
    }
    case SPVM_OP_C_ID_ELSIF: {
      printf("ELSIF\n");
      break;
    }
    case SPVM_OP_C_ID_ELSE: {
      printf("ELSE\n");
      break;
    }
    case SPVM_OP_C_ID_FOR: {
      printf("FOR\n");
      break;
    }
    default: {
      printf("No Match\n");
    }
  }
}

switch文の内部実装はどうなっていますか?

整数のパターンによって、二種類のジャンプテーブルが選択的に使われていると想像します。

整数の範囲が小さい場合

ジャンプ先のアドレスは、連続した整数位置に並べられ、計算量O(1)でジャンプできます。

5 0x1235
6 0x4568
7 NULL
8 NULL
9 0x3289

整数の範囲が大きい場合

ジャンプ先のアドレスは、二分探索が可能なように小さい順に並べられ、計算量O(log n)でジャンプできます。

5     0x1237
6     0x4563
7000  0x8768
10000 0x3284

if文とswitch文はどのように使い分けますか?

if文とswitch文はどのように使い分けるでしょうか?

switch文は、整数にマッチする場合にだけ使います。switch文は、列挙型との相性が非常によいです。

また、マッチさせる数が多い場合は、if文よりも速いです。たとえば、255個のIDで分岐したい場合は、switch文は高速で適しているといえます。

関連情報