2006-01-15-01-お気に入りの横着コード - project-enigma

2006-01-15-01-お気に入りの横着コード

>> Site top >> weblog >> 月別アーカイブ >> 2006年01月のlog >> 2006-01-15-01-お気に入りの横着コード

最終更新日付:2014/01/02 00:00:00


お気に入りの横着コード

2006 年 01 月 15 日

突然だが、以下のコードを見て欲しい。なにをやっているか、わかっていただけるだろうか。(weblog だとインデントが崩れるのは勘弁願いたい)

switch( n ) {    while( true ) {
case 0:             Foo( );
                    if( n == 2 ) break;
case 1:             Bar( );
                    if( n == 0 ) break;
case 2:             Qux( );
                    if( n == 1 ) break;
}                }

人によっては、以下のように書き換えた方が見やすいかもしれない。

switch( n ) {
    while( true ) {
case 0:
        Foo( );
        if( n == 2 ) break;
case 1:
        Bar( );
        if( n == 0 ) break;
case 2:
        Qux( );
        if( n == 1 ) break;
    }
}

いずれにしても奇妙だ...switch と while のブロックが絡み合っている...switch によって、while ブロックの「途中」にいきなり飛び込んでしまうようだ。しかし、これは C/C++ のコードとして完全に合法である。つまり、コンパイルが通り、「書かれている通りに」動作するのだ。しかし、「書かれている通り」とは? そもそも、このコードは何をしようとしているのだろう? なぜこんな書き方をしているのだろう?

n が 0, 1, 2 それぞれの場合でコードを追ってみるとよくわかる。n == 0 の場合、Foo( ), Bar( ) の順に実行されて break、n == 1 の場合、Bar( ), Qux( ), break、そして(ここが肝心なのだ)、n == 2 の場合、Qux( ) を実行した後、while ループによって先頭に戻り、Foo( ) を実行して break する...つまり、これは以下のコードと同じである。

switch( n ) {
case 0:
    Foo( );
    Bar( );
    break;
case 1:
    Bar( );
    Qux( );
    break;
case 2:
    Qux( );
    Foo( );
    break;
}

ようするに、3つのうちから2つの組み合わせがそれぞれ実行されることを利用し、Foo( ), Bar( ), Qux( ) の呼び出しを1回だけしか書かないようにするため(だけ)にこんなことをしているというわけだ。いささか馬鹿げているように感じられるかもしれない。しかし、場合によってはこれは「使える」テクニックだし、そうでなくてもお楽しみという点では合格点だろう。実際、Foo( ) だの Bar( ) だのといったシンプルな呼び出しは説明のためであり、実際のコードはもっと長いから、このテクニックによって長さが半分になるのである。

このテクニックは陰郎の頭の中に突然浮かんだものではない。これは、「ハッカーズ大辞典」という本に載っていた Duff's Device というやつの簡単な応用である。switch 文の case ラベルが while ループの中に飛び込んでしまえるというのを初めて見たときはショックだった...陰郎はこれを大変面白がり、自分のコードに使った。それが冒頭に載せたコードである。久しぶりにそれを見つけたので、懐かしくなってここに書いた次第。

 

コメント

このページにコメントする

 

このページのタグ

Page tag : 開発

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.