148

単純なswitchステートメントが与えられた

switch (int)
{
    case 1 :
    {
        printf("1\n");
        break;
    }

    case 2 : 
    {
        printf("2\n");
    }

    case 3 : 
    {
        printf("3\n");
    }
}

ケース2にbreakステートメントがないということは、ケース3のコード内で実行が続行されることを意味します。これは偶然ではありません。そのように設計されました。なぜこの決定がなされたのですか?これは、ブロックの自動ブレークセマンティクスを持つことと比較してどのような利点がありますか?理論的根拠は何でしたか?

4

9 に答える 9

158

多くの回答は、ステートメントを要求する理由として失敗する能力に焦点を当てているようです.break

C が設計されたとき、これらの構造がどのように使用されるかについての経験がほとんどなかったためです。

Peter Van der Linden は、著書「Expert C Programming」で次のように説明しています。

Sun C コンパイラのソースを分析して、デフォルトのフォールスルーがどのくらいの頻度で使用されたかを確認しました。Sun ANSI C コンパイラのフロント エンドには 244 の switch ステートメントがあり、各ステートメントには平均 7 つのケースがあります。フォールスルーは、これらすべてのケースのわずか 3% で発生します。

つまり、通常のスイッチの動作は97% の確率で間違っています。これはコンパイラだけではありません。反対に、この分析でフォール スルーが使用されたのは、他のソフトウェアよりもコンパイラでより頻繁に発生する状況でした。たとえば、1 つまたは 2 つのオペランドを持つことができる演算子をコンパイルする場合です。 :

switch (operator->num_of_operands) {
    case 2: process_operand( operator->operand_2);
              /* FALLTHRU */

    case 1: process_operand( operator->operand_1);
    break;
}

ケース フォール スルーは欠陥として広く認識されているため、上に示した特別なコメント規則さえあり、lint に「これは実際にはフォール スルーが必要な 3% のケースの 1 つです」と伝えます。

C# が各ケース ブロックの最後に明示的な jump ステートメントを必要とするのは良い考えだったと思います (ステートメントのブロックが 1 つしかない限り、複数のケース ラベルを積み重ねることができます)。C# では、1 つのケースを別のケースにフォールスルーさせることができますgoto

Java が C のセマンティクスから脱却する機会を利用しなかったのは残念です。

于 2008-10-31T06:18:53.567 に答える
31

多くの点で、cは標準のアセンブリイディオムへのクリーンなインターフェイスにすぎません。ジャンプテーブル駆動のフロー制御を作成する場合、プログラマーは「制御構造」を通過するかジャンプアウトするかを選択でき、ジャンプアウトには明示的な命令が必要です。

したがって、cは同じことを行います...

于 2008-10-31T03:06:25.220 に答える
25

Duffのデバイスを実装するには、明らかに次のようにします。

dsend(to, from, count)
char *to, *from;
int count;
{
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}
于 2008-10-31T03:03:07.973 に答える
19

ケースが暗黙的に破られるように設計されている場合、フォールスルーはあり得ません。

case 0:
case 1:
case 2:
    // all do the same thing.
    break;
case 3:
case 4:
    // do something different.
    break;
default:
    // something else entirely.

スイッチがすべてのケースの後に暗黙的に発生するように設計されている場合、それについて選択することはできません。スイッチケースの構造は、より柔軟になるように設計されています。

于 2008-10-31T03:01:23.077 に答える
16

switchステートメントのcaseステートメントは単なるラベルです。

値をオンにすると、switchステートメントは基本的に一致する値を持つラベルに移動します

これは、次のラベルの下のコードにパススルーしないようにするためにブレークが必要であることを意味します。

このように実装された理由については、switchステートメントのフォールスルーの性質が一部のシナリオで役立つ場合があります。例えば:

case optionA:
    // optionA needs to do its own thing, and also B's thing.
    // Fall-through to optionB afterwards.
    // Its behaviour is a superset of B's.
case optionB:
    // optionB needs to do its own thing
    // Its behaviour is a subset of A's.
    break;
case optionC:
    // optionC is quite independent so it does its own thing.
    break;
于 2008-10-31T03:02:43.357 に答える
9

次のようなことを許可するには:

switch(foo) {
case 1:
    /* stuff for case 1 only */
    if (0) {
case 2:
    /* stuff for case 2 only */
    }
    /* stuff for cases 1 and 2 */
case 3:
    /* stuff for cases 1, 2, and 3 */
}

caseキーワードをラベルと考えると、gotoより自然に表示されます。

于 2010-11-12T22:42:22.023 に答える
3

複数のケースで同じコード(または同じコードを順番に実行)を実行する必要がある場合に、コードの重複を排除します。

アセンブリ言語レベルでは、それぞれの間を分割するかどうかは関係ありません。いずれにせよ、フォールスルーケースのオーバーヘッドはゼロです。特定の場合に大きな利点があるため、許可しないでください。

于 2008-10-31T03:01:30.143 に答える
0

ここで多くの人が指定しているように、1 つのコード ブロックが複数のケースで機能できるようにするためです。これは、例で指定した「ケースごとのコードのブロック」よりも、switch ステートメントでより一般的に発生するはずです。

ケースごとにフォールスルーのないコード ブロックがある場合は、おそらく if-elseif-else ブロックの使用を検討する必要があります。

于 2008-10-31T05:29:25.510 に答える