例えば次のような流れのコードがあったとします。
/* 関数(func_*の中身は省略) */ int main(){ int result; result = func_1(); if(result == -1){ return 1; } result = func_2(); if(result == -1){ return 1; } result = func_3(); if(result == -1){ return 1; } result = func_4(); if(result == -1){ return 1; } result = func_5(); if(result == -1){ return 1; } return 0; }
func_1〜func_5の関数をそのまま実行し、チェックをするだけの処理ですが、チェック処理として同じ内容を何度も繰り替えしています。(↓強調表示した部分です)
/* 関数(func_*の中身は省略) */ int main(){ int result; result = func_1(); if(result == -1){ return 1; } result = func_2(); if(result == -1){ return 1; } result = func_3(); if(result == -1){ return 1; } result = func_4(); if(result == -1){ return 1; } result = func_5(); if(result == -1){ return 1; } return 0; }
同じのを何度も書くのは面倒ですし、冗長で見た目も汚いし、修正も手間がかかります。
こんな時、ループを使うと処理の記述の重複を避けることができます。
/* 関数(func_*の中身は省略) */ int main(){ int result; int loop; for(loop = 0; loop < 5; loop ++){ switch(loop){ case 0: result = func_1(); break; case 1: result = func_2(); break; case 2: result = func_3(); break; case 3: result = func_4(); break; case 4: result = func_5(); break; } if(result == -1){ return 1; } } return 0; }
このようにしておくと、後で追加するときや修正する時に楽になります。
もっと簡単に構造のみを書くと、次のようになります。
for(i = 0; i < 10; i++){ /* 共通処理 */ switch(i){ case 0: /* 処理A */ break; case 1: /* 処理B */ break; /* 省略 */ } /* 共通処理 */ }
共通処理の部分に全処理で共通して行うこと、一般的には例外処理・エラー処理などを入れておけば、それぞれの処理A、処理B・・・では処理の記述が不要になります。
for文でセットする数字やcaseで分岐するときの数字はダイレクトに書いてもいいのですが、列挙体を使うことをおすすめします。理由は追加時、挿入時の変更が容易であるからです。(↓「PROC」はprocedureの略)
enum { PROC_START = 0,/* ダミー */ PROC_A, /* 処理A */ PROC_B, /* 処理B */ PROC_C, /* 処理C */ PROC_D, /* 処理D */ PROC_END /* ダミー */ }; /* ---------------- */ for(i = PROC_START; i < PROC_END; i++){ /* 共通処理 */ switch(i){ case PROC_A: /* 処理A */ break; case PROC_B: /* 処理B */ break; /* 省略 */ } /* 共通処理 */ }
というプログラムで、PROC_Gを追加したい時は
enum { PROC_START = 0,/* ダミー */ PROC_A, /* 処理A */ PROC_B, /* 処理B */ PROC_C, /* 処理C */ PROC_D, /* 処理D */ PROC_G, /* 処理G */ PROC_END /* ダミー */ }; /* ---------------- */ for(i = PROC_START; i < PROC_END; i++){ /* 共通処理 */ switch(i){ case PROC_A: /* 処理A */ break; case PROC_B: /* 処理B */ break; /* 省略 */ case PROC_G: /* 処理G */ break; } /* 共通処理 */ }
と、少し追加するだけで済みますし、処理AとBの間にGを入れたい場合は、
enum { PROC_START = 0,/* ダミー */ PROC_A, /* 処理A */ PROC_G, /* 処理G */ PROC_B, /* 処理B */ PROC_C, /* 処理C */ PROC_D, /* 処理D */ PROC_END /* ダミー */ }; /* ---------------- */ for(i = PROC_START; i < PROC_END; i++){ /* 共通処理 */ switch(i){ case PROC_A: /* 処理A */ break; case PROC_G: /* 処理G */ break; case PROC_B: /* 処理B */ break; /* 省略 */ } /* 共通処理 */ }
で、OKです。switch内の処理Gの位置はどこでもいいのですが、せっかく処理順に並んでいるので、AとBの間に入れた方がいいでしょう。ダミーはループ変数のセット、継続条件の指定に使用するために作ったものであり、実際の処理順を入れ替えても、ループの部分は変更することなくプログラムの修正ができます。
PROC_STARTが一回分余分にループを回ることになります。それが困る場合は、PROC_STARTを定義にしておく
#define PROC_START (0) enum { PROC_A = PTOC_START /* 処理A */ PROC_B, /* 処理B */ PROC_C, /* 処理C */ PROC_D, /* 処理D */ PROC_END /* ダミー */ };
か、continueで処理を飛ばしてしまえばOKです。
for(i = PROC_START; i < PROC_END; i++){ /* 共通処理 */ switch(i){ case PROC_START: continue; break; case PROC_A: /* 処理A */ break; case PROC_B: /* 処理B */ break; /* 省略 */ } /* 共通処理 */ }
なお、関数ポインタが使えるのであれば、関数ポインタを使うともっとシンプルになります。
/* 関数(func_*の中身は省略) */ int main(){ int result; int loop; int (*func[])() = {func1, func2, func3, func4, func5}; for(loop = 0; loop < 5; loop ++){ result = func[loop](); if(result == -1){ return 1; } } return 0; }
順番が一定でない場合はwhileやループ変数の足し算のないforを使用します。その場合は毎回処理番号をセットする必要があります。
for(endflag = 0; endflag != 1;){ /* 共通処理 */ switch(i){ case PROC_A: func_a(); /* 処理A */ i = PROC_B; break; case PROC_B: result = func_b(); /* 処理B */ if(result == 1){ /* 処理結果によって分岐 */ i = PROC_C; } else { i = PROC_D; } break; /* 省略 */ case PROC_G: result = func_g(); /* 処理G */ if(result == 1){ /* 処理結果によって分岐 */ endflag = 1; /* 終了 */ } else { i = PROC_A; } break; } /* 共通処理 */ }