2

簡単な質問です。たとえば、オプションが 1000 までのかなり大きなケースで作業する場合: どれが「最良の」方法ですか? 私は特に、より速い結果を望んでいるわけではありません。

switch (foo) {
    case 0: 
        // code ...
        break; 

    // One, two, skip a few...

    case 1000:
        // code ...
}

または、可能な結果を​​分割して、適切なケースステートメントをすばやく見つけることができるもの。同様に:

if (foo < 101) {
    if (foo < 51)
        switch (foo) {}
    else
        switch (foo) {}
} else if (foo > 100 && foo < 201) {

// skipped for convenience 

} else if (foo > 900) {
    if (foo < 951)
        switch (foo) {}
    else
        switch (foo) {}
}

数値が大きい場合は 2 番目の方法の方がはるかに高速だと思いますが、ステートメントを常にチェックしているわけではないため、最初の方法でも簡単に処理できるようです。これらの方法の 1 つが嫌われていますか、それともより良い方法がありますか? これは C の場合ですが、他の言語との整合性を知りたいです。ありがとう!

4

5 に答える 5

9

switchコンパイラがジャンプテーブルを使用してステートメントを実装する場合、ステートメントは非常に高速になる可能性がありますが、これはの特別なシーケンスでのみ可能でありcases、実際には可能性に依存するため、実用的ではない場合がありますcases。コンパイラーはジャンプテーブルを使用する場合と使用しない場合がありますが、このhttp://blog.jauu.net/2010/06/15/GCC-generated-Switch-Jump-Tables/は興味深いものでした。

JUMPテーブルは、オフセットを計算して適切なアドレスにジャンプするだけなので、非常に高速です。

GCCには、-fno-jump-tablesそれを完全に無効にするものがあります。

関数ポインタの配列と特別なインデックスを使用して独自のジャンプテーブルを作成できる場合があります。これにより、コードが非常に高速になりますが、すべての場合に実用的ではありません。スイッチがあり、すべての場合に関数を呼び出すと想像してください。関数ポインタの配列を作成し、安全のためにデフォルトの関数を設定し、スイッチの代わりにfun_table[indice]();、自分の仮想マシンに対してこれを1回実行するだけで済みます。

于 2012-06-21T04:22:30.817 に答える
1

switchステートメントは、基礎となるアセンブリ言語ではgotoとして解釈されることが多いと思います。これにより、最初のメソッドが大幅に高速化されます。

正確な証拠ではありませんが、これはそれをサポートしているようです:http: //en.wikibooks.org/wiki/Optimizing_C%2B%2B/Writing_efficient_code/Performance_improving_features#Case_values_of_switch_statements

于 2012-06-21T04:20:01.177 に答える
1

少なくともコードの可読性の観点から(そして、2番目の例のように、複数の条件を評価する必要があるため、実行するブロックを1つだけ選択するため、速度の観点から)、switchステートメントの方が優れていると思います。

于 2012-06-21T04:22:11.167 に答える
0

どの関数も約1.5の画面に収まるようにすることはお勧めできません。そのため、このような巨大なswitchステートメントはこの法案に収まりません。これを克服するには、ディスパッチテーブルを用意します。必要なのは、配列にインデックスを付けて、呼び出す適切な関数を見つけることだけです。

于 2012-06-21T04:27:00.477 に答える
0

samy.vilar は関数配列を使用した最も洗練されたソリューションを既に提供しているため、情報提供のみを目的としてこれを投稿しています。GCC を使用すると、大文字と小文字の範囲が理解されます。このコードは最終的に 2 番目のソリューションと非常によく似た方法で動作し、バイナリ ツリー コード パスが生成されます (コンパイラの最適化がない場合)。

int             nested_switch(int i)
{
  switch (i) {
    /* i is in the 1..10 range */
  case 1 .. 10:
    switch (i) {
      /* i is in the 0..5 range */
    case 1 .. 5:
      switch (i) {
      case 1:
        break;
      case 2:
        break;
      ...
      case 5:
        break;
      }
    case 5 .. 10:
      switch (i) {
      case 6:
        break;
      case 7:
        break;
      ...
      case 10:
        break;
      }
    }
    /* i is in the 11..20 range */
  case 11 .. 20:
    switch (i) {
      ...
    }
  }

  return 0;
}
于 2012-06-21T11:40:19.773 に答える