Pre- & Post Increment in C#

Pre- & Post Increment in C#

x-- will be 4, but will be 3 at the moment of --x, so it will end being 2, then you'll have

x = 4 - 2

btw, your first case will be x = 4 + 6

Here is a small example that will print out the values for each part, maybe this way you'll understand it better:

static void Main(string[] args)
{
int x = 4;
Console.WriteLine("x++: {0}", x++); //after this statement x = 5
Console.WriteLine("++x: {0}", ++x);

int y = 4;
Console.WriteLine("y--: {0}", y--); //after this statement y = 3
Console.WriteLine("--y: {0}", --y);

Console.ReadKey();
}

this prints out

x++: 4
++x: 6
y--: 4
--y: 2

C# post increment and pre increment

Difference is, what the operator returns:

The post-increment operator "a plus plus" adds one, and returns the old value:

int a = 1;
int b = a++;
// now a is 2, b is 1

The pre-increment operator "plus plus a" adds one, and returns the new value:

    a = 1;
b = ++a;
// now a is 2 and b is 2

Pre and post increment/decrement operators in C#

you are running one of the operands on the result of the other, the result of a increment/decrement is a value - and you can not use increment/decrement on a value it has to be a variable that can be set.

Simultaneous pre-increment and post-increment or mixing pre-post increments

The result of (x++) or (++x) is not actually a variable. It's a value, so:

int y = (++x) + 1;
// evaluates to
int y = (1) + 1;

but

int y = ++x++;
// is equivalent to
int y = ++(x++);
// evaluates to
int y = ++(0);

Difference between pre-increment and post-increment in a loop?

a++ is known as postfix.

add 1 to a, returns the old value.

++a is known as prefix.

add 1 to a, returns the new value.

C#:

string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
Console.WriteLine(++i);
}
Console.WriteLine("");

i = 0;
foreach (string item in items)
{
Console.WriteLine(i++);
}

Output:

1
2
3
4

0
1
2
3

foreach and while loops depend on which increment type you use. With for loops like below it makes no difference as you're not using the return value of i:

for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }

0 1 2 3 4

0 1 2 3 4

If the value as evaluated is used then the type of increment becomes significant:

int n = 0;
for (int i = 0; n < 5; n = i++) { }

Pre & post increment operator behavior in C, C++, Java, & C#

Java and C# evaluate expressions from left to right, and the side-effects are visible immediately.

In C++, the order of evaluation of subexpressions is unspecified, and modifying the same object twice without an intervening sequence point is undefined behavior.

Unexpected post-increment behavior in assignment

For me the best way to understand some behaviour is to check IL generated. In your first case it's

IL_0001:  ldc.i4.s    0A // stack: 10
IL_0003: stloc.0 // a = 10, stack: empty
IL_0004: ldloc.0 // stack: 10
IL_0005: dup // stack: 10, 10
IL_0006: ldc.i4.1 // stack: 10, 10, 1
IL_0007: add // stack: 10, 11
IL_0008: stloc.0 // a = 11, stack: 10
IL_0009: stloc.0 // a = 10, stack: empty
IL_000A: ldloc.0 // stack: 10
IL_000B: call System.Console.WriteLine

You can see that there's still that original value hanging on the stack and so the created 11 gets overwritten in the end.

Let me try to explain it in plain words.

When you are assigning a value to a variable (a = a++) the whole right side of the assignment gets evaluated first in order to guarantee the correct value, that's how it is. So nothing like you get 10, application goes on and increments value when you execute the next line.

Now, imagine post-increment as someone, who first increments a value, but gave you his world that you will get back the original value from the expression. And now you should see why the 11 is overwritten. Increment goes first and in the end, you get the promise original value (as IL proves).

Post-increment within a self-assignment

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 :)



Related Topics



Leave a reply



Submit