16

ウィキペディアでこのコードを見つけました。

#include <stdio.h>

int main(void)
{
  int c;

  while (c = getchar(), c != EOF && c != 'x')
  {
    switch (c)
      {
      case '\n':
      case '\r':
        printf ("Newline\n");
        break;
      default:
        printf ("%c",c);
      }
  }
  return 0;
}

while ループの条件として使用される式に興味があります。

while (c = getchar(), c != EOF && c != 'x')

それが何をするのかは明らかですが、私はこれまでにこの構造を見たことがありません。これはwhileループに固有のものですか? そうでない場合、パーサー/コンパイラーは、コンマ区切り式のどちら側がwhileループのブール値を返すかをどのように判断しますか?

4

5 に答える 5

21

コンマ演算子は、最初のオペランドを評価して結果を破棄し、次に2番目のオペランドを評価してこの値を返す2項演算子です。

これは「シーケンスポイント」でもあり、コードの次の部分が実行される前にすべての副作用が計算されることを意味します。

于 2009-07-16T08:12:07.067 に答える
12

コンマ演算子は、理解するまでは奇妙な獣であり、に固有のものではありませんwhile

表現:

exp1, exp2

評価してexp1から評価exp2して返しますexp2

あなたはそれを頻繁に見ますが、あなたはそれを理解していないかもしれません:

for (i = j = 0; i < 100; i++, j += 2)

からの戻り値を実際に使用しているわけではありませんが"i++, j += 2"、それでもそこにあります。コンマ演算子は、両方のビットを評価して、との両方を変更ijます。

通常の式を使用できる場所であればどこでも使用でき(たとえば、関数呼び出し内のコンマはコンマ演算子ではありません)、必要に応じてコンパクトなソースコードを作成するのに非常に役立ちます。そのように、それは次のようなことを可能にする家族の一部です:

while ((c= getchar()) != EOF) {...}
i = j = k = 0;

等々。

あなたの特定の例のために:

while (c = getchar(), c != EOF && c != 'x')

次のことが発生します。

  • c = getchar()完全に実行されます(コンマ演算子はシーケンスポイントです)。
  • c != EOF && c != 'x'実行されます。
  • コンマ演算子は最初の値(c)を破棄し、2番目の値を「返します」。
  • whileその戻り値を使用してループを制御します。
于 2009-07-16T08:14:47.950 に答える
4

多くの言語では、コンマは常に2番目のオペランドの値になる演算子です。オペランドは左から右に順番に評価されます。

擬似コード:

a = 10
print a = 7 + 8, a * 2

注:print引数をとらないステートメントと見なされるため、後に続くものは単一の式と見なされますa = 7 + 8, a * 2

このように実行されます:

  • 最初の行
    • 入れ10a
  • 二行目
    • 評価7 + 815
    • 評価値(15)を入れますa
    • 評価a * 230
    • オペランドと: ,を使用して演算子を評価します。1530
      • 常に第2オペランドの値(30
    • 評価値を出力(30
于 2009-07-16T08:12:29.280 に答える
2

このコードで、他の答えを少し拡張するには、次のようにします。

EXPRESSION_1 , EXPRESSION_2

EXPRESSION_1が最初に評価され、次にシーケンスポイントがあり、次にEXPRESSION_2が評価され、全体の値がEXPRESSION_2の値になります。

引用したコードにとって、動作保証の順序とシーケンスポイントはどちらも重要です。これらを合わせると、getchar()関数が呼び出され、cの値がテストされる前に、変数cの値が完全に更新されることが確実になります。

于 2009-07-16T08:17:54.277 に答える
1

カンマは演算子です。デフォルトでは、右辺の式の値を返します。評価の順序は、最初に左、次に右になることが保証されています。

更新(Paxのコメントに返信):

ほとんどの演算子と同様に、ユーザー定義型ではオーバーロードできます。

#include <iostream>
#include <string>
using namespace std;

enum EntryType { Home, Cell, Address };

class AddressBookEntryReference {
public:
    AddressBookEntryReference(const string& name, const EntryType &entry)
        : Name(name), Entry(entry) { }
    string Name;
    EntryType Entry;
};

AddressBookEntryReference operator,(const string& name, const EntryType &type) {
    return AddressBookEntryReference(name, type);
}

class AddressBook {
    string test;
public:
    string& operator[](const AddressBookEntryReference item) {
        // return something based on item.Name and item.Entry.

        // just to test:
        test = item.Name;
        return test;
    }
};

int main() {
    // demo:
    AddressBook book;
    cout << book["Name", Cell]  // cool syntax! 
         << endl;
}
于 2009-07-16T08:12:18.937 に答える