C言語 switch文のwikipedia

switch文のWikipediaで

気になる記載があったので、その事について。ただの雑記です。

件の例がこれ。「switchによる分岐は以下のようにdo-while文と組み合わせることも可能である。」とあるんですが。

switch(count)
{
   default:       do {    printf("%d\n", count); count++;
   case 0:                printf("%d\n", count); count++;
   case 1:                printf("%d\n", count); count++;
   case 2:                printf("%d\n", count); count++;
                  } while (count);
}

一見して「ただの無限ループ」にしか思えなかったんですが、、、実際そうでした(^^;。

例として微妙すぎる気が、、、

私の理解ですけど、switch文はコンパイルすると大体こんな感じになるという理解

  1. 条件チェックとラベルにジャンプする命令郡
  2. デフォルトへのジャンプ
  3. default ラベルの定義とラベルに続く文の処理
  4. case ラベル0の定義とラベルに続く文の処理
  5. case ラベル1の定義とラベルに続く文の処理
  6. case ラベル2の定義とラベルに続く文の処理
  7. break時の脱出位置の定義

switch文の本質は最初の二つの処理にしかなくて、後は単なるラベルと処理の集まり。

wikipediaの記載はdo while限定のように感じますが、for文だろうがwhileだろうが書ける、

書けるけど問題がある。という認識。

実際書くとgccやVC++では特に問題なくCompileが通ります。

たとえばこんな。

int i = 1;
    int count = -1;
    switch(count) {
        for (i = 0; i < 10; i++) {
        default:
            printf("D %d %d\n", count, i); count++;
        case 0:
            printf("0 %d %d\n", count, i); count++;
        }
        case 1:
            printf("1 %d\n", count); count++;
        case 2:
            printf("2 %d\n", count); count++;
    }

いろいろ変更して動作を追える様にちょっと情報追加してます。

注意ですが、switchのblock開始から分岐先のラベルまでのコードはjumpされてしまうので実行されません。

forや初期化とループ条件チェック、whileでもループ条件チェックが最初に実行されますが、

それらが条件次第で飛ばされて実行されない事がありえるということです。

このforやwhileの制御が正しくない(?)状況になりえる事が「書けるけど問題がある」とした点です。

ちなみにfor文はcompileされると概ねこんな感じ。

  1. forの1番目の式-初期化
  2. 条件チェックの場所までジャンプ
  3. ループ開始地点の定義
  4. forの処理文
  5. forの3番目の式-更新処理
  6. forの2番目の式-条件チェックとループ開始地点までループ

これがさっきのswitchの中に入るだけって事になります。

なお、先ほどの例であげたプログラムだとforの初期化式と条件チェックまでのジャンプが実行されません。

default ラベルの前にforの開始があるからです。

while/do-while/forで確認してみたけど、普通に想定どおりの動作でしたが

こんな事を百科事典であるWikipediaに書く意味は無いんじゃないかなと思ったりするんですが、、、どうなんでしょ?

すくなくとも言語仕様的にOKなのであれば、do-whileに限定したような書き方をするのは誤りな気がする。

以下余談ですが、利用価値について。

私的に直感的ではないし、使うべきではない様に思うのですが否定だけしててもと思ったので

利用する価値がある場面ってあるかをちょっと考えてみました。

一つは 大きな非常に時間のかかるループをまわすようなプログラムで途中で終了させても復帰できるようにする場合。

たとえば、Ctrl+Cが入ったときに、処理の進行状況とループ回数を記録しておいて、

ループの途中から処理を復帰させたいと思ったときに使える、、、かなぁ?

switch(p) {

default: do{ p=0;

case 0: 処理1; p++

case 1: 処理2; p++

case 2: 処理3; p++

case 3: 処理4; p++

case 4: 処理5; p++

} while(loop_cond);

}

こうしておけば、pとloop_condが保存できれば、再度この処理に突っ込んだときに、

続きが出来るという仕組み。

ただ、これだと

do {

swtich(p){

default: p = 0;

case 0: 処理1; p++

case 1: 処理2; p++

case 2: 処理3; p++

case 3: 処理4; p++

case 4: 処理5; p++

}

} while(loop_cond);

これと本質的には同じ。

ループの度にswitchが入らないって点で処理速度上はswitchの中にループを書いた方が有利なのかな。

coroutineでの処理中断と再開が基本的にプロセス内での話しなので、それを超えたい場合にとか、、、?

後はdo {} while(false); で処理グループをまとめて、

breakによる脱出先を他のケースにしたい場合に使うとか。

swtich(p){

do {

case 1: 処理1; break;

case 2: 処理2; break;

case 3: 処理3; break;

} while(false);

処理4; break;

default: 処理5; break;

}

…goto使った方が飛び先がシンプルに分かる気がす。

こんな感じぐらいしか考えられませんでした。

後はWikipediaにもあるループ展開か。

switch(c % 8) {

do {

default: 処理; –c;

case 7: 処理; –c;

case 6: 処理; –c;

case 5: 処理; –c;

case 4: 処理; –c;

case 3: 処理; –c;

case 2: 処理; –c;

case 1: 処理; –c;

} while(c > 0);

}

なんか他にこういう時に使えるというのがあれば教えてくだされー。