switch文とif文の実行速度やメモリの使用量について


switch文とif文の実行速度やメモリの使用量について

if文はメンテナンス性を考えると効率が悪い方法というのを知っています。

[code]

    enum Act{ AAA, AAB, ... , ZZZ};
    if ( AAA == ch ){...}
    else if( AAB == ch ){...}
    ...
    else if( ZZZ == ch ){...}
    else{...}
    
[/code]

そこで、switch文を使うのですが、、カッコも悪く効率も悪そうです。

[code]

    switch (　ch ){
    case AAA: ... break;
    case AAB: ... break;
    ...
    case ZZZ: ... break;
    default: ... break;
    }
    
[/code]

なぜなら、コンパイルの結果同じバイナリコードが生成されているとしたら  
上から順に比較することになり最悪で26^3回の比較が必要になるからです。  
26^3回がコンピュータにとってたいした数ではないかもしれませんが、極力多くしてみました。  
それに始めて見たときにこのコードに対して、知的さを感じず快く思いませんでした。  
そこで以下のようなコードを考えました。

[code]

    void (*name[])(void*)={ aaa, aab, ... , zzz};
    name[ch](NULL);
    aaa(void* a){}
    aab(void* a){}
    ...
    zzz(void* a){}
    
[/code]

これなら関数になるので抜け出す処理が記述されていても納得ですし。  
caseがどんなに増えてもアクセスは定数時間かと思います。  
巨大なswitch文が一人で居座るわけでなくなるので、ファイルの分割も行いやすくなります。  
分割してコンパイルしていればそれ相応に恩恵を受けるかと思います。  
ただ、ひとつ関数が増えるたびに変更する箇所がenumと配列,caseだけのswitchと比べたら手間になってしまっている気がします。

実際の現場ではどれが利用されて居るのでしょうか。  
内心はif<3~5 switch<10
それ以上では、配列関数ポインタ又は、関数へのポインタの配列、もしくは関数の配列（実は名前を知らない）を利用したほうがよいと思うのですが、規則や効率など総合的に見てこういった書き方はどうなのでしょう。




ifとswitch・・・。「どちらで記述すると他の人に伝わり易いか」以外に比較する必要性を感じていない、に一票。

WindowsやLinuxなどユーザ空間だけでしかプログラミングをした経験が無いと迷い込みやすい「沼」にはまり込んでおられるように思います。

少し視点を変えて、特定マイコン向けの組み込み環境でC言語でプログラミングをしてみると、「効率」とか「最適化」とかいった、今はまだ「何だか良くわからないけどカッコイイ言葉」が切実に現実味のある言葉として身近に感じられるようになると思います。

そこまでするのが億劫なら、マイコン向けコンパイラのドキュメント(特に最適化の説明)を紐解くだけでも有用だと思いますが。




コンパイラがソースコードを解析したとき、`if`の連続を`switch`と同等に処理するか、`switch`を`if`の連続と同等に処理するかは、コンパイラが決めることで、人間が気にする必要はほとんどありません。その`switch`でさえ、`case`の値が単純な数列の場合、ジャンプテーブルの生成まで、コンパイラが自動で行います。

もっと高位の次元で、アルゴリズムをどう実装するか、といった場面では、人間による工夫も必要でしょうが、`if`にするか`switch`にするかといったレベルでは、コンパイラに任せてしまうのがベストです。

だから、人間にとっていちばん読みやすい書き方をしたときに、高速で省メモリなバイナリを生成します。

なぜなら、コンパイラは人間の癖を知っているのです。コンパイラはそのように、人間の癖に合わせて設計されています。

ちなみに3番目に例示された、ジャンプテーブルを自前で用意する、というのが、いちばん良くありません。ジャンプテーブルの配列の引数値がオーバーフローしたとき、アクセス違反が発生したり、想定外のアドレスにジャンプしたりしますので、プログラマが細心の注意を払って実装しなければなりませんし、何より、コンパイラが最適化する余地がなくなります。

