8

昨夜、好奇心旺盛なダフの装置に初めて遭遇しました。私はそれについていくつか読んでいますが、理解するのはそれほど難しいことではないと思います。私が興味を持っているのは、奇妙な構文です(ウィキペディアから):

register short *to, *from;
register int count;
{
  register 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);
  }
}

switch ステートメントの C++ 標準定義を読んでいました(それが古い場合はお知らせください。Open-Std.org に詳しくありません)。私が理解できる限り、case ステートメントは、switch ステートメントで使用する単純化されたジャンプ ステートメントです。

スイッチ自体はネストされた do-while を完全に無視し、ループは case ステートメントを無視します。ループ内でスイッチがジャンプするので、ループが実行されます。スイッチは (8 による除算の) 剰余をカバーするためにあり、ループは均等に割り切れる部分を処理します。これはすべて理にかなっています。

私の質問は、なぜぎこちない構文なのですか? すべての case ステートメントがその中に含まれるようにループを書くことができると思います。標準にはこの動作を禁止するものは何も見当たらず、GCC 4.7 で正しくコンパイルされるため、以下は合法と見なされますか?

register short *to, *from;
register int count;
{
  register int n = (count + 7) / 8;
  switch (count <= 0 ? 8 : count % 8)
  {
    do
    {
      case 0:         *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++;
      default:        ; // invalid count, suppress warning, etc.
    } while(--n > 0);
  }
}

これにより、コードの意図がより明確になります。フィードバックをお寄せいただきありがとうございます。;)

編集:以下に示すように、元のコードは C 用に書かれており、count変数とn変数に暗黙的な int がありました。C++ のタグを付けたので、それを変更しました。

編集 2:無効なカウント値を考慮して、改訂されたサンプル コードを修正しました。

4

3 に答える 3

8

C++11標準を見ると、あなたが尋ねていると思うコードの部分が許可されます。試してみましたか?

最も当てはまると思われるルールは次のとおりです。

注: 通常、switch の対象となるサブステートメントは複合でありcasedefaultラベルは (複合) サブステートメント内に含まれるトップレベルのステートメントに表示されますが、これは必須ではありません。

do実際、これは-を囲む中括弧を取り除き、次のwhileように書くことができることを意味します。

  int n = (count + 7) / 8;
  switch (count % 8) do
  {
      case 0:         *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);

ただし、この行は有効な C++ ではありません。

register n = (count + 7) / 8;

C++ では default-int を使用できません。変数の型を指定または推測する必要があります。


ああ、ここで、フォーマットを壊さずに反復回数を修正します。

  int n = 1 + count / 8;
  switch (count % 8) 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++;
      case 0:                      ;
  } while(--n > 0);
于 2013-01-14T22:11:24.573 に答える
1

はい、合法です。ステートメントのラベルswitchは通常、ステートメントと同じレベルで記述されswitchます。ただし、ループの途中など、複合ステートメント内に記述しても問題ありません。

EDIT : switch ステートメントの本文をラベルで開始する必要はありません。どのコードも有効です。ただし、switch ステートメント自体からはアクセスできないため、ループまたはプレーン ラベルでない限り、コードに到達できません。

このステートメントのもう 1 つの興味深い点swtichは、中括弧がオプションであることです。ただし、その場合、許可されるラベルは 1 つだけです。

  switch (i)
      case 5: printf("High five\n");
于 2013-01-14T22:12:34.807 に答える
1

コードは確かに合法です。for ブロックやループに関する要件はまったくありません。count == 0ただし、上記のループでは適切に処理されないことに注意してください。ただし、これは適切に処理されます。

int count = atoi(ac == 1? "1": av[1]);
switch (count % 4)
{
case 0: while (0 < count) { std::cout << "0\n";
case 3: std::cout << "3\n";
case 2: std::cout << "2\n";
case 1: std::cout << "1\n";
    count -= 4;
    }
}

ラベルcase 0をループ内に配置すると、ネストされたステートメントも誤って実行されます。Duff のデバイスが常にdo-whileループを使用しているのを見てきましたが、境界条件を処理するには上記のコードの方が自然なようです。

于 2013-01-14T22:30:27.610 に答える