switch / case / break / default
| 対応: | C89(1989) |
|---|
整数値や文字などの値に応じて処理を分岐させます。複数の値で処理を切り替える場合、『if / else if』を連ねるより『switch / case』の方がすっきり書けます。
構文
switch (式) {
case 値1:
処理1;
break;
case 値2:
処理2;
break;
case 値3:
case 値4:
処理3; // 値3と値4の両方でこの処理を実行します(フォールスルー)。
break;
default:
デフォルトの処理;
break;
}
キーワード一覧
| キーワード | 概要 |
|---|---|
| switch | 式を評価してマッチするcaseへジャンプします。式には整数型(int、char、enumなど)を使用できます。浮動小数点数や文字列は使えません。 |
| case | 比較する定数値を指定します。コロンに続いて処理を書きます。値は定数(リテラルや定数式)でなければなりません。 |
| break | switchブロックから抜け出します。省略するとそのまま次のcaseの処理が実行されます(フォールスルー)。 |
| default | どのcaseにも一致しなかった場合に実行されます。省略可能ですが、想定外の値への対処として書くことを推奨します。 |
サンプルコード
整数値・char・列挙型の値で処理を分岐します。フォールスルーを使うと複数の値に同じ処理を適用できます。
sample_switch_case.c
#include <stdio.h>
int main(void) {
int day = 3;
switch (day) {
case 1: printf("月曜日\n"); break;
case 2: printf("火曜日\n"); break;
case 3: printf("水曜日\n"); break;
case 4: printf("木曜日\n"); break;
case 5: printf("金曜日\n"); break;
case 6: printf("土曜日\n"); break;
case 7: printf("日曜日\n"); break;
default: printf("無効な値です。\n"); break;
}
char grade = 'B';
switch (grade) {
case 'A': printf("優秀です。\n"); break;
case 'B': printf("良好です。\n"); break;
case 'C': printf("合格です。\n"); break;
default: printf("不合格です。\n"); break;
}
/* フォールスルーで複数の case をまとめます。 */
int month = 4;
switch (month) {
case 1: case 3: case 5: case 7:
case 8: case 10: case 12:
printf("31日あります。\n"); break;
case 4: case 6: case 9: case 11:
printf("30日あります。\n"); break;
case 2:
printf("28日または29日あります。\n"); break;
default:
printf("無効な月です。\n"); break;
}
return 0;
}
コンパイルして実行すると次のようになります。
gcc sample_switch_case.c -o sample_switch_case ./sample_switch_case 水曜日 良好です。 30日あります。
enum と組み合わせる
列挙型(enum)と switch を組み合わせると、状態や種類を整数ではなく名前で管理できます。コンパイラが未処理のケースを警告してくれることもあります。
switch_enum.c
#include <stdio.h>
typedef enum {
CHAR_KENSHIN,
CHAR_KAORU,
CHAR_SANOSUKE,
CHAR_YAHIKO
} CharType;
const char *get_weapon(CharType c) {
switch (c) {
case CHAR_KENSHIN: return "逆刃刀";
case CHAR_KAORU: return "木刀";
case CHAR_SANOSUKE: return "なし(素手)";
case CHAR_YAHIKO: return "竹刀";
default: return "不明";
}
}
int main(void) {
CharType hero = CHAR_KENSHIN;
printf("武器: %s\n", get_weapon(hero));
CharType chars[] = {CHAR_KENSHIN, CHAR_KAORU, CHAR_SANOSUKE, CHAR_YAHIKO};
int n = (int)(sizeof(chars) / sizeof(chars[0]));
for (int i = 0; i < n; i++) {
printf("キャラ %d の武器: %s\n", i, get_weapon(chars[i]));
}
return 0;
}
コンパイルして実行すると次のようになります。
gcc switch_enum.c -o switch_enum ./switch_enum 武器: 逆刃刀 キャラ 0 の武器: 逆刃刀 キャラ 1 の武器: 木刀 キャラ 2 の武器: なし(素手) キャラ 3 の武器: 竹刀
よくあるミス
よくあるミス: break を書き忘れてフォールスルーする
『break』を省略すると次の case の処理まで続けて実行されます。意図しないフォールスルーはバグの原因になります。
switch_fallthrough_ng.c
#include <stdio.h>
int main(void) {
int x = 2;
/* NG: case 2 に break がないので case 3 も実行される */
switch (x) {
case 1:
printf("1 です。\n");
break;
case 2:
printf("2 です。\n");
/* break; を書き忘れた! */
case 3:
printf("3 です。\n"); /* x == 2 でもここが実行される */
break;
default:
printf("それ以外です。\n");
break;
}
/* OK: 各 case に break を書く */
switch (x) {
case 1: printf("1 です。\n"); break;
case 2: printf("2 です。\n"); break;
case 3: printf("3 です。\n"); break;
default: printf("それ以外です。\n"); break;
}
return 0;
}
修正後は次の通りです。
gcc switch_fallthrough_ng.c -o switch_fallthrough_ng ./switch_fallthrough_ng 2 です。 3 です。 2 です。
概要
『switch』は内部的にジャンプテーブルを使って実装されることが多く、多くの分岐がある場合に『if / else if』より効率的に動作します。『break』を書き忘れると、意図せず次の『case』の処理も実行されます(フォールスルー)。意図的なフォールスルーでない場合は必ず『break』を書いてください。
『switch』の式には整数型(『int』・『char』・『enum』など)しか使えません。文字列や浮動小数点数での分岐はできないため、その場合は『if / else』を使用してください。
関連する値をグループ化する場合は『enum(列挙型)』と組み合わせると、整数の代わりに名前で値を区別できます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。