30

前置/後置演算子が実際にどのように機能するか教えてもらえますか? 私はオンラインでたくさん探してきましたが、何も見つかりませんでした。

私が言えることから、prefex は最初にインクリメントし、次に操作を実行してから割り当てます。
Postfix は最初に操作を行い、次に割り当て、次にインクリメントします。

しかし、私は自分のコードに少し問題があります:

int x, y;
x = 1;
y = x + x++; // (After operation y = 2)(x=2)

しかし、私がするとき:

y = x++ + x; // (After operation y = 3)(x=2)

これらの操作が異なる理由はわかりません。2 つの質問があります。

  • 違いを説明していただけますか?

  • これは他の演算子のプレフィックスにどのように適用されますか?

4

7 に答える 7

62

この質問はかなりの量尋ねられます。誰かがこの質問をするたびに、非常に多くの人が間違った答えを投稿することに注意してください。プログラミングの本を書き、それによって他の人に虚偽を教える人を含め、多くの人がこれらの演算子がどのように機能するかについて間違った考えを持っています。ここで他の答えを注意深く読んでください。

C#の動作の正しい分析については、以下を参照してください。

i++と++iの違いは何ですか?

C ++の場合、副作用が観察されている場合、どのような動作も正しい動作です。C ++は、増分の副作用がいつ表示されるかを定義しません。2つのコンパイラはそれを異なる方法で行うことができます。

従うべき良いルールは、どの言語でも副作用が発生する順序に依存しないことですが、信頼性が低いため、C++では確かにそれに依存しないでください。

あなたの特定のケースを見るには:

int x, y;     
x = 1;     
y = x + x++; 

xとyが両方とも2であると報告します。これはC#では正しいです。C#での正しい動作は次のとおりです。

  • yを変数として評価する
  • xを値として評価します-それは1です
  • x++を値として評価します。これにより、xが変数として評価され、元の値である1を取得し、その値である2をインクリメントし、次に2をxに割り当てて、元の値である1になります。
  • 1 + 1、つまり2を評価します
  • yに2を割り当てます。

したがって、C#ではxとyはどちらも2です。

C ++でも同じことができますが、右から左の順序で加算を評価することができます。つまり、次のことを行うことが許可されています。

  • x++を値として評価します。これにより、xが変数として評価され、元の値である1を取得し、その値である2をインクリメントし、次に2をxに割り当てて、元の値である1になります。
  • xを値として評価します-それは2です
  • 1 + 2、つまり3を評価します
  • yを変数として評価する
  • yに3を割り当てます。

C++でもこれを行うことができます。

  • x++を値として評価します。これにより、xが変数として評価され、元の値である1を取得し、その値をインクリメントします。これは2です...ここではステップが欠落しています...そして元の値である1になります。
  • xを値として評価します-それは1です
  • 1 + 1、つまり2を評価します
  • xに2を割り当てます-前に欠落していたステップ。
  • yを変数として評価する
  • yに2を割り当てます。

したがって、C ++では、コンパイラー作成者の気まぐれに応じて、yを3または2として取得できます。C#では、常にyが2であることがわかります。C++では、インクリメントの割り当ては、発生する限り、いつでも発生する可能性があります。C#では、インクリメントの割り当ては、インクリメントされた値が計算された、元の値が使用される前に行われる必要があります。(実行中のスレッドから観察した場合。別のスレッドからこのようなものを観察しようとしている場合、すべての賭けは無効になります。)

2番目の例では:

y = x++ + x; 

C#では、必要な動作は次のとおりです。

  • yを変数として評価する
  • x++を値として評価します。これにより、xが変数として評価され、元の値である1を取得し、その値である2をインクリメントし、次に2をxに割り当てて、元の値である1になります。
  • xを値として評価します-それは2です
  • 1 + 2、つまり3を評価します
  • yに3を割り当てます。

したがって、C#の正解は、yが3、xが2であるということです。

この場合も、C++はこれらの手順を任意の順序で実行できます。C++では次のことが許可されています。

  • xを値として評価します-それは1です
  • x++を値として評価します。これにより、xが変数として評価され、元の値である1を取得し、その値である2をインクリメントし、次に2をxに割り当てて、元の値である1になります。
  • 1 + 1、つまり2を評価します
  • yを変数として評価する
  • yに2を割り当てます。

繰り返しますが、C ++では、正解は、コンパイラー作成者の気まぐれに応じて、yが2または3であるということです。C#では、正解はyが3であるということです。

于 2011-10-18T18:58:59.733 に答える
29
  • C#では、のオペランドは+左から右の順序で評価されます。
  • CおよびC++では、のオペランドの評価順序+は指定されていません。

C#の場合、例は次のように機能します。

 y = x + x++;
     ^ x is 1
         ^ x is increased to 2, but the postfix increment returns the old value (1)
 y = 2

 y = x++ + x;
     ^ x becomes 2, but postfix increment returns the old value (1)
           ^ x is now 2 here
 y = 3
于 2011-10-18T18:55:23.627 に答える
7

CおよびC++
の場合:出力は未指定です。

リファレンス-C++03標準:

セクション5:式、パラ4:

特に明記されている場合を除き[たとえば、&&および||の特別な規則]、個々の演算子のオペランドと個々の式の部分式の評価の順序、および副作用が発生する順序は指定されていません。

C99セクション6.5。

"演算子とオペランドのグループ化は構文で示されます。72)後で指定される場合を除き(関数呼び出し()、&&、||、?:、およびコンマ演算子の場合)、部分式の評価の順序と順序どの副作用が発生するかはどちらも特定されていません。」

于 2011-10-18T19:01:46.990 に答える
6

どちらの場合も、xが使用された後に増分が適用されました。最初に、次のように評価されました:y = 1 + 1(2にインクリメント)

2番目に

y = 1(2にインクリメント)+2。

そのため、さまざまな回答が得られました。

于 2011-10-18T18:57:15.357 に答える
4

x++++xには、結果(または値) と副作用の両方があります。

議論を整数型オペランドに限定すると、 の結果x++の現在の値が何であれxです。副作用として、 1ずつインクリメントxされます。

x = 0;
y = x++;

結果はx== 1 および== 0 になります (およびが整数型であるとy仮定)。xy

の場合++x結果は 1 に の現在の値を加えたものになりますx副作用として、 1ずつインクリメントxされます。

x = 0;
y = ++x;

結果はx== y== 1 になります。

C と C++ が C# と異なるのは、オペランドが評価されるときと副作用が適用されるときです。C# では、式のオペランドが常に左から右に評価されることが保証されています。C および C++ は、、、、コンマ&&、および関数呼び出し演算子の左から右への評価のみを保証します。他のすべての演算子については、オペランドが評価される順序は指定されていません。 ||?:()

同様に、C# では、 と の副作用はx++++x式が評価された直後に適用されますが、C と C++ では、次のシーケンス ポイントの前に副作用を適用する必要があるだけです。

x = x++評価に関する C# のルールは、a = b++ * b++、 、などの式が明確に定義されていることを保証しますa[i] = i++が、C および C++ 言語の定義では、そのような式は未定義の動作になる (どんな結果もあり得る) と明示的に述べています。

于 2011-10-18T21:31:36.597 に答える
3

x +x++およびx+++ xは、依存したくない病理学的副作用の例です。x++と++xはどちらもxをインクリメントしますが、xを追加する際の評価の順序は定義されていません。コンパイラーは、最初に評価する「サイド」を選択できます。

于 2011-10-18T18:56:37.573 に答える
0

検討:

y = x + x++;

その動作が定義されているかどうかに関係なく (C および C++ では未定義ですが、C# では明確に定義されているようです)、何をしようとしても、それを表現するためのより良い方法が必ずあります。

厳密な左から右への評価を想定している場合、上記は次のように記述できます。

y = x * 2;
x ++;

=その意味は、 、*、および意味を知っている読者には明確で明白で++あり、コードの将来のメンテナーはあなたを追い詰めようとはしません。

または、コンパイラが効率的なコードを生成することを信頼していない場合は、x + xまたは書くことができますが、そのような不信は通常見当違いです。x << 1

あなたが主張するなら、次のように書くことさえできます:

y = x++ * 2;

これは私の個人的な好みとしては少し簡潔ですが、それでも明確です。

他の誰かのコードを理解したい場合 (これは、プログラマーが多くの時間を費やしていることは確かです)、複雑な式を理解することが重要になる可能性があります。しかし、独自のコードを作成する場合は、キーストロークを節約すること (または、演算子の優先順位チャートをどれだけよく知っているかを誇示すること) よりも、明快さの方が重要です。

于 2011-10-19T04:04:09.120 に答える