例えば次のような流れのコードがあったとします。
/* 関数(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;
}
/* 共通処理 */
}