10

c/c++ の switch ステートメントがジャンプ テーブルにコンパイルされることがあると理解しています。私の質問は、それを保証するための経験則はありますか?

私の場合、私は次のようなことをしています:

enum myenum{
MY_CASE0= 0,
MY_CASE0= 1, 
.
.
.
};

switch(foo)
{
  case MY_CASE0:
  //do stuff
  break;
  case MY_CASE1:
  //do stuff
  break;
 .
 .
 .
}

1 から n までのすべてのケースを順番にカバーします。ジャンプテーブルにコンパイルされると想定しても安全ですか? 元のコードは長くて厄介なif elseステートメントだったので、少なくともある程度は読みやすくなりました。

4

2 に答える 2

16

優れたコンパイラは、ジャンプ テーブル、チェーンされた if/else、またはその組み合わせのいずれかを選択できます。設計が不十分なコンパイラは、そのような選択をしない可能性があり、スイッチ ブロックの非常に悪いコードを生成することさえあります。しかし、適切なコンパイラであれば、スイッチ ブロックの効率的なコードを生成する必要があります。T

ここでの主な決定要因は、数値が大きく離れている場合にコンパイラが if/else を選択する可能性があることです [そして、自明ではなく (たとえば、2、4、8、16、256 などで除算すると) より近い値に変更されます]。

 switch(x)
 {
    case 1:
     ...
    case 4912:
     ...
    case 11211:
     ...
    case 19102:
     ...
 }

少なくとも 19102 * 2 バイトのジャンプ テーブルが必要です。

一方、数値が互いに接近している場合、コンパイラは通常、ジャンプテーブルを使用します。

たとえそれif/elseが設計のタイプであっても、通常は「二分探索」を行います - 上記の例を取ると:

 if (x <= 4912)
 {
     if (x == 1)
     {
        ....
     }
     else if (x == 4912)
     {
         .... 
     }
 } else {
     if (x == 11211)
     {
         ....
     }
     else if (x == 19102)
     {
         ...
     }
 }

ケースがたくさんある場合、このアプローチは非常に深くネストされ、人間はおそらく 3 ~ 4 レベルの深さで迷子になるでしょう (それぞれが範囲の MIDDLE のある時点から始まることに注意してください)。 log2(n) によるテストの数。ここで、n は選択肢の数です。それは確かに単純なアプローチよりもはるかに効率的です

if (x == first value) ... 
else if (x == second value) ... 
else if (x == third value) ... 
..
else if (x == nth value) ... 
else ... 

特定の値が if-else チェーンの先頭に置かれている場合、これはわずかに改善される可能性がありますが、それは、コードを実行する前に最も一般的な値を判断できることを前提としています。

ケースにとってパフォーマンスが重要な場合は、2 つの代替案をベンチマークする必要があります。しかし、私の推測では、コードをスイッチとして記述するだけで、コードがより明確になり、同時に、高速ではないにしても、少なくとも同じ速度で実行されると思います。

于 2013-06-12T10:04:22.797 に答える