Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post-increment within a self-assignment

I understand the differences between i++ and ++i, but I'm not quite sure why I'm getting the results below:

static void Main(string[] args) {     int c = 42;     c = c++;     Console.WriteLine(c);   //Output: 42 } 

In the above code, as this is assigning the variable to itself and then incrementing the value, I would expect the result to be 43. However, it is returning 42. I get the same result when using c = c--; as well.

I realise I could just simply use c++; and be done with it, but I'm more curious why it is behaving the way that it is. Can anyone explain what's happening here?

like image 607
Siyual Avatar asked Nov 18 '15 15:11

Siyual


People also ask

What is the example of post increment?

In the Post-Increment, value is first used in an expression and then incremented. Here, suppose the value of 'x' is 10 then the value of variable 'a' will be 10 because the old value of 'x' is used.

How does post pre increment work?

Pre-increment and Post-increment concept in C/C++? Decrement operator decrease the value by one. Pre-increment (++i) − Before assigning the value to the variable, the value is incremented by one. Post-increment (i++) − After assigning the value to the variable, the value is incremented.

What does post increment mean?

Post-increment means that the variable is incremented AFTER it has been evaluated for use in the expression.

How do you post increment?

The post increment operator is used to increment the value of some variable after using it in an expression. In the post increment the value is used inside the expression, then incremented by one. if the expression is a = b++; and b is holding 5 at first, then a will also hold 5.


2 Answers

Let’s take a look at the intermediary language code for that:

IL_0000:  nop IL_0001:  ldc.i4.s    2A IL_0003:  stloc.0     // c IL_0004:  ldloc.0     // c 

This loads the constant integer 42 onto the stack, then stores it into the variable c, and loads it immediately again onto the stack.

IL_0005:  stloc.1 IL_0006:  ldloc.1 

This copies the value into another register, and also loads it again.

IL_0007:  ldc.i4.1 IL_0008:  add 

This adds the constant 1 to the loaded value

IL_0009:  stloc.0     // c 

… and stores the result (43) into the variable c.

IL_000A:  ldloc.1 IL_000B:  stloc.0     // c 

Then the value from the other register is loaded (that’s still 42!) and stored into the variable c.

IL_000C:  ldloc.0     // c IL_000D:  call        System.Console.WriteLine IL_0012:  nop IL_0013:  ret 

Then the value (42) is loaded from the variable, and printed.


So what you can see from this is that while c++ increments the variable by one after the result was returned, that incrementing happens still before assinging the value to the variable. So the sequence is more like this:

  1. Get value from c
  2. Post-increment c
  3. Assign previously read value to c

And that should explain why you get that result :)


To add one more example, since this was mentioned in a comment that was since deleted:

c = c++ + c; 

This works very similarly: Assuming an initial value of 2 again, the left side of the addition is evaluated first. So the value is read from the variable (2), then c is incremented (c becomes 3). Then the right side of the addition is evaluated. The value of c is read (now 3). Then the addition takes place (2 + 3) and the result (5) is assigned to the variable.


The takeaway from this is that you should avoid mixing increment and decrement operations in normal expressions. While the behavior is very well defined and makes absolute sense (as shown above), it is still sometimes difficult to wrap your head around it. Especially when you assign something to the same variable that you increment in the expression, this becomes confusing quickly. So do yourself and others a favor and avoid increment/decrement operations when they are not completely on their own :)

like image 133
poke Avatar answered Sep 20 '22 03:09

poke


According to the MSDN page on C# operators the assignment operator (=) has lower precedence than any primary operator, such as ++x or x++. That means that in the line

c = c++; 

the right hand side is evaluated first. The expression c++ increments c to 43, then returns the original value 42 as a result, which is used for the assignment.

As the documentation you linked to states,

[The second form is a] postfix increment operation. The result of the operation is the value of the operand before it has been incremented.

In other words, your code is equivalent to

// Evaluate the right hand side: int incrementResult = c;   // Store the original value, int incrementResult = 42 c = c + 1;                 // Increment c, i.e. c = 43  // Perform the assignment: c = incrementResult;       // Assign c to the "result of the operation", i.e. c = 42 

Compare this to the prefix form

c = ++c; 

which would evaluate as

// Evaluate the right hand side: c = c + 1;                 // Increment c, i.e. c = 43 int incrementResult = c;   // Store the new value, i.e. int incrementResult = 43  // Perform the assignment: c = incrementResult;       // Assign c to the "result of the operation", i.e. c = 43 
like image 36
CompuChip Avatar answered Sep 22 '22 03:09

CompuChip