Coder Perfect

Why is I += i++) equal to 0 when I = 0?

Problem

Take the following code (usable as a Console Application):

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

I yields a value of 0. I was expecting two (as some of my colleagues did). The compiler most likely builds some type of structure that causes I to be zero.

I expected 2 since, according to my logic, the right-hand expression will be evaluated first, incrementing I by 1. It is then added to i. It adds 1 to 1 because I is already 1. As a result, 1+1=2. Obviously, this isn’t the situation.

Could you describe what the compiler does or what happens at runtime? What causes the outcome to be zero?

Some-sort-of-disclaimer: I am well aware that you will not (and probably should not) use this code. I know I never will. Nevertheless, I find it is interesting to know why it acts in such a way and what is happening exactly.

Asked by Peter

Solution #1

This:

int i = 0;
i += i++

Can be viewed as you are performing (this is a big simplification):

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

What happens in reality is more complicated; see MSDN, 7.5.9 Postfix increment and decrement operators:

Because of the order of precedence, the postfix ++ comes before +=, but the result is unusable (as the previous value of I is used).

A more comprehensive breakdown of I += i++ to its constituent pieces necessitates understanding that both += and ++ are not atomic (that is, neither is a single operation), despite their appearance. Temporary variables, copies of I before the operations take place – one for each operation – are used to implement them. (The temporary variables for ++ and += will be called iAdd and iAssign, respectively.)

So, here’s a closer approximation of what’s going on:

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;

Answered by Oded

Solution #2

Disassembly of the running code:

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)

It generates the same output as the following code:

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

The second code is being disassembled (just to prove they are the same)

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

The majority of users are unaware of, or forget, that they may view the final in-memory assembly code using the Visual Studio Disassembly window. It displays the machine code that is running; it is not CIL.

While debugging, remember to use the following:

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

The postfix++ specifies that we want to increase the operand’s value after the evaluation… which is obvious… but the meaning of “after the evaluation” is a bit ambiguous.

So, what does “following the evaluation” imply:

So, what does it mean when you say: I += i++;?

It’s equivalent to I = I + i++.

The following is the evaluation order:

It’s not like the increment is being thrown away.

What does the expression I = i++ + I mean?

This differs from the previous example. The increase has an effect on the third i.

The following is the evaluation order:

Answered by Miguel Angelo

Solution #3

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

is assessed in the following way:

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

i.e., the i++ expression and the += command both change i.

The operands of the += statement, on the other hand, are

Answered by dtb

Solution #4

To begin, i++ returns 0. Then I is raised by one. Finally, I is set to its initial value of 0 plus the value returned by i++, which is also zero. 0 + 0 equals 0.

Answered by Jong

Solution #5

a tree of syntax The evaluation unfolds as the recursion pops back up the tree from the bottom, despite the fact that the expression’s tree is walked from top to bottom conceptually.

// source code
i += i++;

// abstract syntax tree

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

The root node += is taken into account first. That is the most important component of the statement. The left operand of += must be evaluated in order to identify where the variable will be stored and to acquire the prior value of zero. The right side must then be assessed.

The ++ operator on the right side is a post-incrementing operator. It only has one operand, I which is evaluated as a source of value as well as a storage location. The operator evaluates I and finds 0; as a result, a 1 is stored in that position. In keeping with its semantics of returning the prior value, it returns 0 in this case.

Control has now reverted to the += operator. It now has all of the information it needs to finish its mission. It knows where to save the result (i’s storage location), as well as the prior value and the value to add to the prior value, which is 0. As a result, I’m left with $0.

C#, like Java, has cleansed a particularly obnoxious element of the C language by reversing the evaluation order. The most evident sequence that coders are likely to expect is left-to-right, bottom-up.

Answered by Kaz

Post is based on https://stackoverflow.com/questions/13516689/for-i-0-why-is-i-i-equal-to-0