30

C++ のステートメントで使用できるのは数値のみであることがわかったので、C++ のswitchステートメントと多数の 's の間には、もっと深い違いがあるに違いないと思いましたif-else

したがって、私は自問しました:

  • (どのように)実行速度、コンパイル時間の最適化、および一般的なコンパイルの点でswitch異なりますか? if-elseif-elseifここでは主に MSVC について話しています。
4

2 に答える 2

40

A switch is often compiled to a jump-table (one comparison to find out which code to run), or if that is not possible, the compiler may still reorder the comparisons, so as to perform a binary search among the values (log N comparisons). An if-else chain is a linear search (although, I suppose, if all the relevant values are compile-time integral constants, the compiler could in principle perform similar optimizations).

于 2010-04-07T22:19:19.433 に答える
8

多くの場合、switch ステートメントは、コンパイラの最適化の一般的なソースです。つまり、それらがどのように扱われるかは、コンパイラで使用する最適化設定によって異なります。

switch ステートメントをコンパイルする最も基本的な (最適化されていない) 方法は、それを一連のif ... else if ...ステートメントとして扱うことです。コンパイラがスイッチを最適化する一般的な方法は、次のようなジャンプ テーブルに変換することです。

if (condition1) goto label1;
if (condition2) goto label2;
if (condition3) goto label3;
else            goto default;
label1:
  <<<code from first `case statement`>>>
  goto end;
label2:
  <<<code from first `case statement`>>>
  goto end;
label3:
  <<<code from first `case statement`>>>
  goto end;
default:
  <<<code from `default` case>>>
  goto end;
end:

この方法が高速である理由の 1 つは、条件内のコードが小さいためです (したがって、条件が誤って予測された場合の命令キャッシュ ペナルティが小さくなります)。また、「フォールスルー」の場合は、実装がより簡単になります (コンパイラーはgoto endステートメントを省略します)。

コンパイラは、(ラベルでマークされた場所への) ポインターの配列を作成することでジャンプ テーブルをさらに最適化し、その配列へのインデックスとして切り替えている値を使用できます。これにより、コードからほぼすべての条件が削除されます (切り替えている値がケースのいずれかと一致するかどうかを検証するために必要だったものを除く)。

注意点: ネストされたジャンプ テーブルは生成が難しく、一部のコンパイラは作成を試みることさえ拒否します。そのため、最大限に最適化されたコードが重要な場合は、switch別の内部にa をネストしswitchないでください (特に MSVC がネストされたswitches をどのように処理するかは 100% わかりませんが、コンパイラのマニュアルで説明されているはずです)。

于 2010-07-19T15:16:17.460 に答える