8

重複の可能性:
If/Else If ではなく、なぜ Switch/Case なのか?

Cのステートメントがコンパイラによってどのようswitch() case:にアセンブラ オペコードに変換されるかを理解したいと思います。

if then else具体的には、一連のブランチとの違いを理解することに興味があります。

性能比較がメインです。

語彙に関するいくつかの単語: 私はアセンブラーの主な概念に精通しており、より単純なシステムのためにずっと前にアセンブラーでコーディングしていましたが、x86 アセンブラーのセマンティックについては確かに何もしていません。したがって、直接のアセンブラ出力は役に立ちません。疑似コードの方がはるかに好まれます。

4

4 に答える 4

6

コンパイラのさまざまなヒューリスティックに応じて、生成されたコードは単なる "if else if" ステートメントのチェーンになる可能性があります。ケースのスペースが小さい場合、コンパイラはジャンプ テーブルを作成できます。次に例を示します。

switch (foo) {
case 0:
    a();
case 1:
    b();
case 2:
    c();
case 3:
    d();
default:
    e();
}

次のようなものに翻訳できます。

if (foo < 0 || foo > 3) goto label_default;
else goto internal_jump_table[foo];

internal_jump_table = { label_0, label_1, label_2, label_3 };
label_0: a();
label_1: b();
label_2: c();
label_3: d();
label_default: e();

他にも実行できる最適化があります。等しいかどうかをチェックする代わりに、コンパイラは if ステートメントの階層を構築して、正しい値を二分探索することができます。または、ジャンプ テーブルが適切な値が多数あり、通常の検索が行われる外れ値がいくつかある場合もあります。または、ジャンプ テーブルが 2 つだけの場合もあります。

于 2012-09-21T13:02:00.540 に答える
6

ifコンパイラは、同等の一連の/else ifステートメントとして実装することを決定するか、分岐テーブルを使用して最適化することを決定できます。これは、ブランチの数や、チェックするすべての値を含む最小範囲のサイズなど、いくつかのパラメーターに依存します。

更新:少なくとも 4 つ以上のスイッチ ケースがない限り、通常、コンパイラはわざわざブランチ テーブルを作成しないということをどこかで読んだことを覚えています。以下の Stephane Rouberol の有益なコメントは、このしきい値を GCC 用に構成する方法を具体的に説明しています。

于 2012-09-21T12:58:09.523 に答える
2

一般的な応答は、常に「場合による」です。パフォーマンスは、プラットフォーム/CPU タイプ、コンパイラ、コンパイラ オプションなどに依存する場合があります。

私は、適切な状況が与えられた場合、switch()構造の複雑さは log(n) になると思います。ここで、n はcase:ステートメントの数です。これは「二分探索」によって達成されます。

このページには多くの詳細があります (Microsoft のコンパイラに焦点を当てていますが、一般的な考え方は一般的に当てはまると思います)。

于 2012-09-21T13:01:07.870 に答える
1

「十分な」数を考慮する(単純なif / else ifswitch casesの代わりに、コンパイラが分岐テーブルを生成することを選択できるようにするのに十分な数):

  • switch-case は、実行されるコードの正しいブロックに一定時間 (O(1)) アクセスします。

  • 一方、一連のif/else ifステートメントには線形時間があります (O( n ) ここで、nは評価する条件の数 (ifステートメント)、n >= 「十分な大きさ」の場合)

更新:もちろん、これらの考慮事項はコンパイラの最適化を考慮していません!

于 2012-09-21T13:17:23.570 に答える