Serviceを読んで理解し、同意したものとみなします。スタック・オーバーフローはプログラマーとプログラミングに熱心な人のためのQ&Aサイトです。2万件-2switch文とif文の実行速度やメモリの使用量についてif文はメンテナンス性を考えると効率が悪い方法というのを知っています。){...}else{...}そこで、switch文を使うのですが、、カッコも悪く効率も悪そうです。break;}なぜなら、コンパイルの結果同じバイナリコードが生成されているとしたら上から順に比較することになり最悪で26^3回の比較が必要になるからです。26^3回がコンピュータにとってたいした数ではないかもしれませんが、極力多くしてみました。それに始めて見たときにこのコードに対して、知的さを感じず快く思いませんでした。そこで以下のようなコードを考えました。a){}これなら関数になるので抜け出す処理が記述されていても納得ですし。caseがどんなに増えてもアクセスは定数時間かと思います。巨大なswitch文が一人で居座るわけでなくなるので、ファイルの分割も行いやすくなります。分割してコンパイルしていればそれ相応に恩恵を受けるかと思います。ひとつ関数が増えるたびに変更する箇所がenumと配列,caseだけのswitchと比べたら手間になってしまっている気がします。実際の現場ではどれが利用されて居るのでしょうか。それ以上では、配列関数ポインタ又は、関数へのポインタの配列、もしくは関数の配列(実は名前を知らない)を利用したほうがよいと思うのですが、規則や効率など総合的に見てこういった書き方はどうなのでしょう。票1ifとswitch・・・。「どちらで記述すると他の人に伝わり易いか」以外に比較する必要性を感じていない、に一票。WindowsやLinuxなどユーザ空間だけでしかプログラミングをした経験が無いと迷い込みやすい「沼」にはまり込んでおられるように思います。視点を変えて、特定マイコン向けの組み込み環境でC言語でプログラミングをしてみると、「効率」とか「最適化」とかいった、今はまだ「何だか良くわからないけどカッコイイ言葉」が切実に現実味のある言葉として身近に感じられるようになると思います。そこまでするのが億劫なら、マイコン向けコンパイラのドキュメント(特に最適化の説明)を紐解くだけでも有用だと思いますが。|11コンパイラがソースコードを解析したとき、ifの連続をswitchと同等に処理するか、switchをifの連続と同等に処理するかは、コンパイラが決めることで、人間が気にする必要はほとんどありません。そのswitchでさえ、caseの値が単純な数列の場合、ジャンプテーブルの生成まで、コンパイラが自動で行います。高位の次元で、アルゴリズムをどう実装するか、といった場面では、人間による工夫も必要でしょうが、ifにするかswitchにするかといったレベルでは、コンパイラに任せてしまうのがベストです。人間にとっていちばん読みやすい書き方をしたときに、高速で省メモリなバイナリを生成します。コンパイラは人間の癖を知っているのです。コンパイラはそのように、人間の癖に合わせて設計されています。ちなみに3番目に例示された、ジャンプテーブルを自前で用意する、というのが、いちばん良くありません。ジャンプテーブルの配列の引数値がオーバーフローしたとき、アクセス違反が発生したり、想定外のアドレスにジャンプしたりしますので、プログラマが細心の注意を払って実装しなければなりませんし、何より、コンパイラが最適化する余地がなくなります。|7極端な例を用意したのはわかりますが、実際の現場を想定するのであれば、26^3の分岐(分岐先ではなく分岐自身)が実行時間に対して支配的だとすると設計が悪い可能性があり、設計を見直します。optimizationを行います。PGOにより分岐の出現パターンに応じた最適化を期待します。支配的でないのであれば、他の部分のパフォーマンスチューニングに力を注ぎ、分岐に関しては書きやすいように書きます。CPPマクロを使用したテーブルなど。PGOはコンパイルの際に、実際に実行したプロファイル結果を参考に最適化を行うものです。コードの分離メモリの組み込みといった最適化が行われます。ステートメント内の特定の値が他の値よりも頻繁に使用されているかどうかを、ガイド付き最適化のプロファイルで検出できます。ステートメントから取得できます。命令でも行うことができます。switch文のどちらを選んでも関係なく、また比較順序やcaseの記述順序についても最適化されます。巨大なswitch文が一人で居座るわけでなくなるので、ファイルの分割も行いやすくなります。分割してコンパイルしていればそれ相応に恩恵を受けるかと思います。分割す‌​ればコンパイルも早くなるだろうし。コンパイル時間を気にされていて、ソースコードを分割することを検討されていると解釈しました。今どきのプロセッサでのコンパイル時間は大したことがありません。C言語では各ソースコードに対して#includeなどプリプロセッサの実行し直しとなるため、ソースコードを分割するとコンパイル時間は増加します。これはあくまで質問文で言及されているコンパイル時間に関するコメントであり、一般論としては既に述べているように設計を見直すべきです。|4本当に26^3通りの分岐を行いたいのでしょうか?17576個のenumシンボルと17576個の分岐先関数を用意するのでしょうか?私が過去にやったことがあるのは、JIS漢字コードからUnicodeへの変換やその逆変換を行うために、二分岐検索を用いたルックアップテーブルを作成したことがあるくらいです。文字コードの変換の例でいうと、元の値は16ビット値でしたので、65536通りです。これを別の65536通りの値に変換するというものですが、このような用例では、処理を分岐したいわけでなく、値を変換したいだけなので、配列から値を取り出すとか、検索や演算で求めるだけで済むわけです。実際の現場と仰っていますが、26^3個の分岐先の関数が、それぞれ関係のない別の処理を行うという状況はあまりありません、入力値であるchの値に応じて、ちょっとだけ違う似たような処理を行うのであれば、分岐先の関数を必要に応じてカテゴリー毎に何種類かに分けて、引数としてchを受け取る関数を用意すれば、大半のchを一つの関数で受け持つことができるでしょう。ここでいうchが、ウィンドウメッセージやイベントやコマンドの番号の様なものだとして、17576種ものコマンドがあるかというと、実際の現場ではあまりないでしょう。仮にあるとしても、chが数千種から数万種の値を取り得るという前提であれば、グループ番号とサブコマンド番号に分けるというのを検討してみます。上位8ビットをグループ番号、下位8ビットをサブコマンド番号とすることを考えます。符号無し8ビット整数であることが明らかならば、境界値チェックは必要なく、256個の配列を用いてジャンプテーブルを構成すればいいでしょう。一段目の分岐をジャンプテーブルで行い、二段目の分岐をswitchで行うというもの、ありえない設計ではないと思います。あとは、机上の議論ではなく、質問者が、具体的にどんな問題を解決したいかによって、どういう方法を採用するのが適しているかは変わってきます。個の銅バッジ机上の議論でもない。あるファイルで二万行コメントが多いわけでもなくて何で長いのか見てみたら、switch塊だった。分割すればコンパイルも早くなるだろうし。コメントを書いたり、有意義に使える行数が増えるはずなのになぜと思った。88%case文と見積もったのは誤算だと思う。30~40%ぐらいでよかったと思ってる。質問するにあたり、どうでもいい実行速度で質問するわけにはいかない。自分はどう変換されたかまで、知りたかった。12:33余談ですが、switch塊といえば、以前勤めていた会社で、256回ループの内側で256分岐のswitchというのを見たことがあります。私の見立てでは、単にそれを書いたプログラマの経験不足だという印象でした。Java等の高級言語からC/C++へ下りてきた人と、アセンブリ言語のような低級言語からC/C++へ上がってきた人では、考え方が変わってくると思います。アセンブリ言語経験者は、自分の書いたCのコードが、どのような機械語に展開されるか、無意識のうちに想像しながら書く習慣が付いています。速度やメモリの制限が厳しいのは、組込系に多いですので、そういうテクニックを身につけたいと思ったら、アセンブリ言語をやってみるといいかもしれません。すると、コンパイラの気持ちになってCが書けます。述べましたが、最近のコンパイラは並の人間より賢いですから、ifかswitchかを比べるのはあまり意味がありません。コンパイラが今ほど賢くなかった時代はありましたが、もはや15年かそれ以上前のバッドノウハウとなっています。|回答スタック・オーバーフローに参加してくれて、ありがとうございます!質問の回答を共有してください。回答を説明し、自分の検討結果も共有してください。意見を述べること(意見を述べるなら、参照リソース、自分の経験で意見をサポートしてください)さらにサポートが必要な場合このヘルプを参考してください。“回答を投稿”をクリックすることで利用規約、プライバシーポリシー、及びクッキーポリシーに同意したものとみなされます。タグが付いた他の質問を参照するか、自分で質問をする。最初に記述すると4静的型付と動的型付のメモリの動きを理解したい。質問のフィードこのRSSフィードを購読するには、このURLをコピーしてRSSリーダーに貼り付けてください。