i = 0の場合、なぜ(i + = i ++)が0に等しいのですか?


253

次のコードを使用します(コンソールアプリケーションとして使用可能)。

static void Main(string[] args)
{
    int i = 0;
    i += i++;
    Console.WriteLine(i);
    Console.ReadLine();
}

の結果iは0です。2を期待していました(同僚の何人かはそうでした)。おそらく、コンパイラーは何らかの結果をiゼロにする構造を作成します。

私が2を期待した理由は、私の考えでは、右側のステートメントが最初に評価され、iに1を加算するためです。iは既に1であるため、1に1が加算されます。したがって、1 + 1 = 2です。明らかに、これは何が起こっているのかではありません。

コンパイラーが実行すること、または実行時に何が起こるかを説明できますか?結果がゼロになるのはなぜですか?

ある種の免責事項:このコードを使用しない(そして使用すべきでない)ことは承知しています。私は絶対にしないでしょう。それにもかかわらず、なぜそれがそのような方法で機能するのか、そして正確に何が起こっているのかを知るのは興味深いことです。


57
期待される結果は1ではありませんか?i(0)+ = i ++(1)したがって、0 + = 1 = 1
修正は

11
期待どおりに動作します
SteveはD

177
この質問のバリエーションはいくつ質問されますか?
mowwwalker

20
Preincrementationはacction実行する前に値をインクリメントします私は+ = ++ iのあなたに1を与えるだろうが
Pierluc SS

21
なぜ皆が前と後のインクリメントに焦点を合わせているのですか?「奇妙な」ことは、の左側のが、右側が評価される前に「キャッシュ」されることです。これは、たとえば次の場合にコピー操作が必要になるため、直感に反しています。i+=iオブジェクトのがています。(誤解しないでください。これ0が正しい標準準拠の回答であることを示すことに同意します。)
JohnB

回答:


425

この:

int i = 0;
i += i++

あなたがしているように見ることができます(以下は全体的な単純化です):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

実際に起こることはそれよりも複雑です-MSDN7.5.9 Postfixインクリメントおよびデクリメント演算子を見てください:

x ++またはx--形式のPostfixインクリメントまたはデクリメント操作のランタイム処理は、次のステップで構成されます。

  • xが変数として分類されている場合:

    • xが評価されて変数が生成されます。
    • xの値が保存されます。
    • 選択された演算子は、保存されたxの値を引数として呼び出されます。
    • 演算子によって返された値は、xの評価によって指定された場所に格納されます。
    • 保存されたxの値は、演算の結果になります。

優先順位のため、後置++前に発生することに注意してください +=にありますが、結果は(以前の値iが使用されているため)未使用になる。


i += i++構成されているパーツをより完全に分解するには、両方にアトミック+=++はない(つまり、どちらも単一の操作ではない)ことを知っている必要があります。これらが実装される方法には、一時変数、i操作が行われる前のコピーが含まれます-操作ごとに1つ。(私は名前iAddiAssign、一時的に使用される変数のために+++=、それぞれ)。

したがって、何が起こっているかにより近い近似は次のようになります。

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;

3
@Oded ステートメントの評価++が完了する前に操作が行われます。したがって+=、値を上書きします。これは何が起こったのですか?
Anirudh Ramanathan 2012

6
実際@Odedその:int i = 0; i = i + 1; (postfix) i = 0; (assignment)。そのステートメントのどこかでiを使用すると、その時点で1と評価されます。
12

@Cthulhu-本質的に。その答えによってDTBは細部に入ります。
2012年

6
これは買わない。@yoriyの答えははるかに正確です。一つには、あなたの答えで、あなたは最後の行がそうでi+1あるのに対し、それはそうあるべきだと言いますi=i+1。それは何i++ですか?
リクライニング

3
答えの最初の部分は冗長です。あなたの最後のコードサンプルは私見でそれをすることができました。+1。
corazza 2012年

194

実行中のコードの逆アセンブル:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

同等のコード

次のコードと同じコードにコンパイルされます。

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

2番目のコードの分解(同じであることを証明するためだけ)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

分解ウィンドウを開く

ほとんどの人は、Visual Studioの逆アセンブリウィンドウを使用して最終的なインメモリアセンブリコードを表示できることを知らない、または覚えていません。実行されているマシンコードを示していますが、CILではありません。

デバッグ中にこれを使用します。

Debug (menu) -> Windows (submenu) -> Disassembly

では、postfix ++で何が起こっているのでしょうか?

postfix ++は、評価後にオペランドの値をインクリメントすることを示しています...誰もが知っていることです...少し混乱するのは、「評価後」の意味です。

「評価後」どういう意味ですか:

  • 同じコード行でのオペランドの他の使用法に影響を与える必要があります。
    • a = i++ + i 2番目のiは増分の影響を受けます
    • Func(i++, i) 2番目に影響を受ける
  • 同じ行での他の使用法は||andのような短絡演算子を尊重し&&ます:
    • (false && i++ != i) || i == 0 3番目のiは評価されないため、i ++の影響を受けません

だから意味は何i += i++;ですか?

と同じです i = i + i++;

評価の順序は次のとおりです。

  1. ストアi + i(つまり0 + 0)
  2. iを増分する(iは1になる)
  3. ステップ1の値をiに割り当てます(iは0になります)

増分が破棄されているわけではありません。

の意味は何i = i++ + i;ですか?

これは前の例と同じではありません。3番目iは増分の影響を受けます。

評価の順序は次のとおりです。

  1. ストアi(つまり0)
  2. iを増分する(iは1になる)
  3. ステップ1 + iの値を格納(つまり、0 + 1)
  4. ステップ3の値をiに割り当てます(iは1になります)

22
+ 1 ++-完全なハードコア解剖用。チャック・ノリスは誇りに思うでしょう:) OPはMonoポートではなくIntel上にあると
思い込んでいると思い

19
C#には式の評価順序が明確に定義されており、オブジェクトコードはその順序を実装するだけです。マシンコード出力は、評価順序の理由や説明ではありません。
Kaz

8
マシンコードにより、評価の順序がIMOにどのように実装されるかを簡単に理解できます。
ケビン

5
@StuartLC私はあなたがそこでやったことを見ます。ただし、賛成投票が破棄されたことは残念です。
Steffan Donal

2
a++ + aa + a++これはもはや純粋な数学ではないためと同じではありません。代数における可換性の法則は、変数が式の途中で値を変更する可能性を考慮していません。プログラミングが関数型プログラミングの場合、数学はプログラミングにきちんと対応します。そしてそれでも、表現上の制限のために。たとえば、浮動小数点数は実数のように動作する場合とそうでない場合があります。副作用がない場合でも、数学の実数に適用される可換性と結合性の法則は、浮動小数点数を超えます。
Kaz

61
int i = 0;
i += i++;

次のように評価されます。

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

つまり、i2回変更されます。1回はi++式によって、もう1回は+=ステートメントます。

しかし、+=ステートメントのオペランドは

  • i評価の前の値i++(の左側+=)および
  • i評価の前の値i++(の右側+=)。

ああ、これは素晴らしい説明です。逆ポーランド記法を使用してスタックベースの計算機で作業したときのことを思い出します。
ネイサン

36

最初にi++0を返しますi。次に、1ずつインクリメントします。最後iに、i0を加えた初期値に0を加えた値をi++返します。0 + 0 = 0。


2
しかし、そうではi += i++;ないi = i++;ので、i++(0)の値はに追加されi、「返さiれる値i++に設定される」のではありません。さて、問題は、にi++返された値を追加iするiと、インクリメントされた値とインクリメントされない値のどちらになるかです。答えは、私の友人です。仕様書に書かれています。
Daniel Fischer

はい、修正します。しかし、とにかくi = 0最初から、はとi += something同等i = 0 + somethingですi = something
ジョン

32

これは、抽象構文ツリーの左から右へのボトムアップ評価です。概念的には、式のツリーは上から下にウォークされますが、再帰が下からツリーを上にポップアップするにつれて評価が展開されます。

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

評価は、ルートノードを検討することから始まります+=。それが表現の主成分です。の左のオペランドを+=評価して、変数を格納する場所を決定し、ゼロである以前の値を取得する必要があります。次に、右側を評価する必要があります。

右側はポストインクリメント++演算子です。オペランドは1つiあり、値のソースと値が格納される場所の両方として評価されます。演算子はi、を評価、検索し0、結果として1その場所に格納します。以前の値を返します0意味論に従って、以前の値を返します。

これで制御は+=オペレーターに戻ります。これで、操作を完了するためのすべての情報が得られました。結果を保存する場所(の保存場所i)と以前の値を認識しており、以前の値に追加する値、つまりを持っています0。そう、iゼロになります。

Javaと同様に、C#は評価の順序を修正することにより、C言語の非常に限定的な側面をサニタイズしました。左から右、ボトムアップ:プログラマーが予期する可能性が最も高い順序。


+1は:私はすべてのコーダ...私はそれがこのようなものと同じであると予想されないことを期待することを除いて、あなたに同意SetSum(ref i, Inc(ref i))してint SetSum(ref int a, int b) { return a += b; }int Inc(ref int a) { return a++; }...もちろん、私はこれ以上のことを期待しています。
ミゲルアンジェロ

また、私が期待したものと矛盾しています!それは等しくないだろうSet(ref i, Sum(i, Inc(ref i)))int Set(ref int a, int b) { return a = b; }してint Sum(int a, int b) { return a + b; }
ミゲルアンジェロ

ありがとう。あなたは私が修正しなければならない私の答えの欠陥/不完全さを示唆しています。
Kaz

の問題SetSumは、左のオペランドを評価せずi、アドレスのみを取得するため、オペランドを完全に左から右に評価することとは異なります。のようなものが必要ですSetSum(ref i, i, PostInc(ref i))。の2番目の引数SetSumは、追加iする値ですi。ここでは、の以前の値を指定するために使用します。SetSumただint SetSum(ref int dest, int a, int b) { return dest = a + b; }です。
Kaz、

+ =演算子では混乱が生じます(少なくとも私にとって)。代入演算子には右から左への評価があるため(たとえば、a = b = c = d)... + =が同じルールに従うと想像できます。アトミック操作として(SetSumメソッドで行ったように)...しかし、実際に起こることは、C#a += ba = a + b...に変換されて++演算子がアトミックでないことを示すということです...
ミゲルアンジェロ


17

ポストインクリメントメソッドは次のようになります。

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

したがって、基本的にを呼び出すとi++iは増分しますが、元の値はあなたの場合に返され、0が返されます。


12

簡単な答え

int i = 0;
i += i++;
// Translates to:
i = i + 0; // because post increment returns the current value 0 of i
// Before the above operation is set, i will be incremented to 1
// Now i gets set after the increment,
// so the original returned value of i will be taken.
i = 0;

12

i ++の意味:iの値を返し、それをインクリメントします。

i + = i ++は、iの現在の値を取ることを意味します。i ++の結果を追加します。

次に、開始条件としてi = 0を追加します。i + = i ++は次のように評価されます。

  1. 私の現在の値は何ですか?それは0です。i++の結果を追加できるように保存します。
  2. i ++を評価します(これはiの現在の値なので0に評価されます)
  3. 保存された値をロードし、ステップ2の結果をそれに追加します。(0から0を追加)

注:ステップ2の最後では、iの値は実際には1です。ただし、ステップ3では、インクリメントされる前のiの値をロードすることにより、値を破棄します。

i ++とは対照的に、++ iは増分された値を返します。

したがって、i + = ++ iは1を返します。


それは完全な助けです
ソンシャ

11

修正後のインクリメント演算子++は、変数に式の値を指定し、返されたゼロ(0)の値に割り当てられiたインクリメント再度実行して、インクリメントされた値(1)を上書きし、ゼロを取得します。インクリメント演算子の詳細については、++演算子(MSDN)をご覧ください。



8

++接尾辞はi、インクリメントする前に評価し、評価する+=だけですi 1回ます。

したがって、0 iの後置形式++が使用されるため、インクリメントされる前に評価および使用される0 + 0 = 0 。取得するi最初の増分、(接頭辞フォームを使用++i)。

(また、メモ:0 +(0 + 1)= 1なので、1のみを取得する必要があります)

参照:http : //msdn.microsoft.com/en-us/library/sa7629ew.aspx(+ =)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx(++)


8

C#が行っていること、および混乱の「理由」

また、値が1になることも期待していましたが、その点についての調査により、いくつかの点が明確になりました。

次の方法を検討してください。

    static int SetSum(ref int a, int b) { return a += b; }

    static int Inc(ref int a) { return a++; }

i += i++同じだと思っていましたSetSum(ref i, Inc(ref i))。このステートメントの後のiの値は1です。

int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1

しかし、私は別の結論に達しました... i += i++実際には同じi = i + i++です...したがって、これらの関数を使用して、別の同様の例を作成しました:

    static int Sum(int a, int b) { return a + b; }

    static int Set(ref int a, int b) { return a = b; }

これを呼び出した後Set(ref i, Sum(i, Inc(ref i)))、iの値は0になります

int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0

これは、C#が何をしているかを説明するだけでなく、多くの人々が私と一緒に混乱した理由も説明しています...


2
これを元の回答に追加してください。個別の回答として使用してもメリットはありません。
casperOne 2012年

2
これは、逆コンパイルされたコードに関するものなので、他の回答を汚すことはありませんでした。どう思いますか?他の回答を編集して、これを追加する必要がありますか?たぶん、これをプリペンドする...わからない!提案をありがとう!
ミゲルアンジェロ

7

これについて私がいつも覚えている良いニーモニックは次のとおりです。

式の後にある場合++以前の値を返します。したがって、次のコード

int a = 1;
int b = a++;

1だったのaは、後に立って増加する前の 1 だっからです。人々はこのポストフィックス表記法を呼び出します。あり、事前物事は正確に反対で修正表記は、以下の場合スタンドの前に、式はそれがあると値を返した後の動作を:++ a++

int a = 1;
int b = ++a;

b ここに2つあります。

したがって、コードでは、これは

int i = 0;
i += (i++);

i++(上記のように)0を返します0 + 0 = 0

i += (++i); // Here 'i' would become two

スコットマイヤーズは、「効果的なC ++プログラミング」におけるこれら2つの表記法の違いについて説明しています。i++(postfix)は内部的に値iwasを記憶し、prefix-notation(++i)を呼び出して古い値を返しますi。これが、常にループ++i内で使用する必要がある理由ですfor(ただし、最近のコンパイラはすべてループ内に変換i++++iれていると思いforます)。


1
私はテストしましたがint i = 0; i += (++i)i2つではなく1つに設定されています。それはあなたが書いた場合、という事実は変更されません。代わりに、接尾辞の接頭辞を使用しているので、あまりにも私には理にかなってi += (++i)に出てi = i + (++i)i前に評価され++i、その結果、i = 0 + (++i)そして最終的にi = 0 + 1
Wutz 2013

6

正しいあなたの質問に対する唯一の答えは次のとおりです。それは未定義だからです。

わかりました、あなたが皆私を燃やす前に...

あなたはみなi+=i++、結果としてが大丈夫で論理的である理由を答えましたi=0

私はあなたの答えの1つ1つに反対票を投じようと誘惑されましたが、計算した評判のヒットは高すぎるでしょう。

なぜ私はあなたたちにそんなに怒っているのですか?あなたの答えが説明するもののためではありません。
私が読んだすべての答えは、不可能を説明するために多大な努力を払っていました、拍手!

しかし、結果は何ですか?それは直感的な結果ですか?それは許容できる結果ですか?

あなた方一人一人が「裸の王」を見て、どういうわけかそれを合理的な王として受け入れました。

あなたはすべて間違っています!

i+=i++; 結果 0は未定義です。

もしそうなら言語評価メカニズムのバグ..またはさらに悪い!デザインのバグ。

証拠が欲しい?もちろん欲しい!

int t=0; int i=0; t+=i++; //t=0; i=1

これは...直感的な結果です!最初にt値を割り当てて評価したので、評価と割り当ての後で初めて、事後操作が発生しました-合理的ではありませんか?

それは合理的ですか:i=i++i=i同じ結果が得られiますか?

一方t=i++、のt=i結果は異なりますi

事後操作は、ステートメントの評価後に行われるべきものです。
したがって:

int i=0;
i+=i++;

私たちが書いた場合も同じでなければなりません:

int i=0;
i = i + i ++;

したがって、以下と同じです。

int i=0;
i= i + i;
i ++;

したがって、以下と同じです。

int i=0;
i = i + i;
i = i + 1;

1合理的な考え方で行った場合、コンパイラのバグまたは言語設計のバグを示さない結果-ただし、MSDNおよび他の多くのソースは、「ちょっと-これは未定義です!」

さて、次に進む前に、私が与えたこの例のセットでさえ、誰もサポートも認めもしません。しかし、これは直感的で合理的な方法による結果であったはずです。

コーダーは、アセンブリがどのように記述または翻訳されているかを知る必要はありません。

言語定義を尊重しない方法で書かれている場合-それはバグです!

最後に、これをWikipediaからコピーしました。インクリメントおよびデクリメント演算子
インクリメント/デクリメント演算子はオペランドを変更するため、同じ式内でそのようなオペランドを複数回使用すると、未定義の結果が生成される可能性があります。たとえば、x − ++ xなどの式では、減算演算子とインクリメント演算子をどの順序で実行する必要があるかが明確ではありません。このような状況は、コンパイラーによって最適化が適用されるとさらに悪化し、その結果、操作の実行順序がプログラマーの意図とは異なるものになる可能性があります。

したがって。

正解は、これは使用すべきではないということです!(未定義なので!)

はい..-C#コンパイラが何らかの方法で正規化しようとしても、予測できない結果になります。

言語の正常な動作または明確に定義された動作として文書化されたすべての動作を説明するC#の文書は見つかりませんでした。私が見つけたのは正反対です!

[ Postfixインクリメントおよびデクリメント演算子のMSDNドキュメントからコピー:++および- ]

後置演算子が関数の引数に適用される場合、引数の値は、関数に渡される前にインクリメントまたはデクリメントされることが保証されいません。詳細については、C ++標準のセクション1.9.17を参照してください。

保証されていない単語に注意してください...

その答えが傲慢に思われる場合は許してください-私は傲慢な人ではありません。私は何千人もの人々がここに学びに来て、私が読んだ答えは彼らを誤解させ、彼らの論理と主題の理解を損なうと考えています。


100%をフォローしているのかわかりませんが、C ++のドキュメントを参照していますが、私の質問はC#に関するものでした。そのドキュメントはこちらです。
Peter 14年

私は私の回答でC#を参照していました。指定したリンクから:x ++またはx--の結果は操作前のxの値ですが、++ xまたは--xの結果は操作後のxの値です。どちらの場合も、演算後のx自体は同じ値になります。明確にするので、これは...テストケースではありません示してi=++iから異なる結果を提供しますi=i++。したがって、私の答えは立っています。
GY 2014年

ああ、わかりましたが、C ++のドキュメントを参照すると混乱します。では、仕様が正しく実装されていないということですか。
ピーター

いいえ、私が言っていることは、それが仕様に従って未定義であり、undefinedを使用すると、未定義の結果になることです。
GY 2014年

C ++では未定義ですが、C#は操作後に同じ値になるはずだと言っていますが、違いますか?これはundefinedと同じではありません(ただし、使用しないことに同意します。免責事項を参照してください。何が起こっているのかを理解しようとしていました)。
ピーター

4

変数の後の++演算子は、それを後置インクリメントにします。インクリメントは、ステートメントの他のすべて、追加と割り当ての後に発生します。代わりに、変数の前に++を置くと、iの値が評価される前に起こり、期待される答えが得られます。


2
これ++はステートメントの後ではなく 、+=ステートメント の実行に発生+=ます。これが、による++getオーバーライドの効果です+=
dtb

++ iを使用すると、実際には2ではなく1になります(私のもともと「期待される答え」)。
ピーター

式の前または後のインクリメントにより、割り当てが変更を+= 上書きするようです。
Steven Lu

4

計算の手順は次のとおりです。

  1. int i=0 // 0に初期化
  2. i+=i++ //方程式
  3. i=i+i++ //コンパイラによって方程式を単純化した後
  4. i=0+i++ // i値の置換
  5. i=0+0 //以下で説明するように、i ++は0です
  6. i=0 //最終結果i = 0

ここでは、最初の値iは0です。WKT i++は何もありません。最初にi値を使用してから、i値を1 ずつインクリメントします。したがってi、計算中に値0を使用してi++から、1ずつインクリメントします。したがって、結果は値になります。の0。


3

2つのオプションがあります。

最初のオプション:コンパイラがステートメントを次のように読み取る場合、

i++;
i+=i;

結果は2です。

ために

else if
i+=0;
i++;

結果は1です。


5
どちらも実際の結果ではありません。
Steven Lu

3

非常に注意してください:C FAQをお読みください:あなたがやろうとしていること(代入と++同じ変数の混合)が指定されていないだけでなく、定義もされていません(つまり、コンパイラーが評価するときに何でもできることを意味します! 「妥当な」結果)。

セクション3をお読みください。セクション全体は一読の価値があります!特に3.9は、詳細不明の影響を説明しています。3.3節では、「i ++」などでできることとできないことを簡単にまとめています。

コンパイラーの内部に応じて、0、2、1、またはそれ以外の何でも取得できます。そして、それは未定義なので、彼らがそうすることは問題ありません。


oops、c#...一部の人がコードを逆アセンブルするために通過した「gcc」に追われました。
Olivier Dulac

1
C#も見逃しましたが、とにかく答えが気に入りました。
Iain Collins

1
@Iain:おかげで、私もそれが可能な答えを維持する価値があったと信じて、多くの人がこのことについて(またはそのことについて知らない偉大最もsubjcetに関する知識を持つ人々のが同じに行っていたユーズネットのベストタイムから、よくある質問更新する場所)
Olivier Dulac

3

上記の回答には多くの優れた推論があります。私は小さなテストを行っただけで、あなたと共有したいと思います

int i = 0;
i+ = i++;

ここで結果iは0件の結果を表示しています。ここで、以下のケースを検討してください。

ケース1:

i = i++ + i; //Answer 1

以前、私は上記のコードがこれに似ていると思ったので、最初は一見すると答えは1になり、実際のiの答えは1になります。

ケース2:

i = i + i++; //Answer 0 this resembles the question code.

ここで、i ++が追加前に実行する機会があった以前のケースとは異なり、インクリメント演算子は実行パスに含まれません。

これが少しお役に立てば幸いです。ありがとう


2

Cプログラミング101のタイプの観点からこれに答えることを望んでいます。

それはこの順序で起こっているように私に見えます:

  1. iは0と評価され、結果としてi = 0 + 0インクリメント操作がi++「キューに入れられます」が、0への割り当てはiまだ行われていません。
  2. 増分i++が発生します
  3. 上記の割り当てi = 0が行われ、#2(ポストインクリメント)が行ったであろうものを効果的に上書きします。

今、#2は実際には決して発生しない可能性があります(おそらく発生しないでしょうか?)。いずれにせよ、他のより知識のある答えは、結果が正しく、C#標準に準拠していることを示していますが、C / C ++でここで何が起こるかは定義されていません。

どのようにそしてなぜ私の専門知識を超えていますが、以前に評価された右側の割り当てがポストインクリメントの後に発生するという事実は、おそらくここで混乱しています。

さらに、私が信じている++i代わりにi++そうしなければ、結果が2になるとは思わないでしょう。


1
プレインクリメントバージョンは、2C ++での結果を生成します:ideone.com/8dH8tf
Steven Lu

それは理にかなっている。しかし、事前増分は事後増分よりもわずかに複雑な状況です。
gkimsey

2

簡単に言えば、

i ++は、「+ =」演算子の完了後に「i」に1を追加します。

必要なのは++ iなので、「+ =」演算子が実行される前に「i」に1が追加されます。


0
i=0

i+=i

i=i+1

i=0;

次に、1がに追加されiます。

i + = i ++

だから、1を追加する前にii私たちは前に1を追加した場合のみ、0の値を取ったi値0を取得します。

i+=++i

i=2

-4

答えはにiなります1

方法を見てみましょう:

当初i=0;

次に、値にi +=i++;基づいて計算している間0 +=0++;、次のように0+=0なります0。したがって、演算子の優先順位に従って最初に実行され、結果はになります。

次に、増分演算子はとして適用され0++0+1の値はにiなります1


3
この答えは間違っています。あなたが行うときので、あなたは1を取得することはありません0 += 0++;割り当てが増加した後である++が、iの値がの前に解釈して++ポストオペレータであるので、(。
PhoneixS

2
申し訳ありませんが、これは正しくありません。私の質問を読んで、私は結果があなたがコードを実行した場合、あなたはそれが効果的に0で表示されます0であると言う表示されます
ピーター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.