Self-determination post-increment

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

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

In the above code, since this assigns the variable to itself and then increments the value, I expect the result to be 43 . However, it returns 42 . I get the same result when using c = c--; .

I understand that I can just use c++; and do with it, but I'm more curious why it behaves the way it is. Can someone explain what is going on here?

+31
c # post-increment pre-increment
Nov 18 '15 at 15:27
source share
6 answers

Let's look at the intermediary language code for this:

 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 and then saves it in the variable c and immediately loads it onto the stack.

 IL_0005: stloc.1 IL_0006: ldloc.1 

This copies the value to another register and 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 saves the result of (43) in the variable c .

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

Then the value is loaded from another register (this is still 42!) And stored in 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 value of the variable by one after the result has been returned, this increase happens even before the value of the variable is set. So the sequence looks something like this:

  • Get value from c
  • Post increment c
  • Assign previously read value c

And that should explain why you get this result :)




To add another example, as it was mentioned in a comment that was deleted:

 c = c++ + c; 

This works very similarly: if you first enter the initial value of 2, the left side of the addition is evaluated first. Thus, the value is read from variable (2), then c increases ( 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 conclusion from this is that you should avoid mixing the increase and decrease operations in normal expressions. Although the behavior is very clearly defined and makes perfect sense (as shown above), it is still difficult to wrap your head around you. Especially when you assign something to the same variable that you are increasing in the expression, it gets confusing quickly. So do yourself and others a favor and avoid increment / decrement operations when they are not completely on their own :)

+32
Nov 18 '15 at 15:34
source share

According to the MSDN page on C # statements, the assignment operator ( = ) has lower priority than any primary statement, for example ++x or x++ . That means in line

 c = c++; 

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

Like state-related documentation,

[The second form is the postfix increment operation. The result of the operation is the value of the operand before it is increased.

In other words, your code is equivalent

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

Compare this with the prefix form

 c = ++c; 

which will be evaluated as

 // Evaluate the right hand side: c = c + 1; // Increment c, ie c = 43 int incrementResult = c; // Store the new value, ie int incrementResult = 43 // Perform the assignment: c = incrementResult; // Assign c to the "result of the operation", ie c = 43 
+19
Nov 18 '15 at 15:30
source share

The docs talk about the postfix state:

The result of the operation is the value of the operand before it has been increased.

This means that when you do:

 c = c++; 

You are actually reassigning 42 to c , and why you see console printing 42 . But if you do this:

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

You will see pin 43 .

If you look at what the compiler generates (in debug mode), you will see:

 private static void Main(string[] args) { int num = 42; int num2 = num; num = num2 + 1; num = num2; Console.WriteLine(num); } 

Which more clearly displays rewriting. If you look in Release mode, you will see that the compiler optimizes the whole call:

 private static void Main(string[] args) { Console.WriteLine(42); } 
+4
Nov 18 '15 at 15:29
source share

... because it assigns the variable to itself, and then increments the value ...

No, that’s not what he does.

The post -increment operator increments this variable and returns the old value . The pre -increment operator increments this variable and returns a new value .

So your c++ increments c to 43, but returns 42, which is then assigned to c again.

+3
Nov 18 '15 at 15:33
source share

The expression on the right side of the assignment is evaluated completely, then the assignment is performed.

  c = c++; 

Same as

  // Right hand side is calculated first. _tmp = c; c = c + 1; // Then the assignment is performed c = _tmp; 
+3
Nov 18 '15 at 15:43
source share

I think I understand what the initial questionnaire was thinking. They thought (I think) that postincrement means incrementing a variable after evaluating the whole expression, for example. what

 x = a[i++] + a[j++]; // (0) 

coincides with

 { x = a[i] + a[j] ; i += 1 ; j += 1; } // (1) 

(and admittedly equivalent) and that

 c = c++; // (2) 

means

 { c = c ; c +=1 ; } // (3) 

So what

 x = a[i++] + a[i++]; // (4) 

means

 { x = a[i] + a[i] ; i += 2 ; } // (5) 

But this is not so. v++ means incrementing v right away, but use the old value as the value of the expression. So, in case (4), the actually equivalent instruction

 {int t0 = a[i] ; i += 1 ; int t1 = a[i] ; i += 1 ; x = t0 + t1 ; } // (6) 

As others noted, statements like (2) and (4) are well defined in C # (and Java), but they are not defined correctly in C and C ++.

In C and C ++ expressions, such as (2) and (4), which modify a variable and also use it in some other way, they are usually undefined, which means that the compiler is welcome (in terms of language laws) to translate them in general, for example, to transfer money from your bank account to the author of the compiler.

+3
Nov 18 '15 at 23:59
source share



All Articles