74

I am a little confused about how the C# compiler handles pre- and post increments and decrements.

When I code the following:

int x = 4;
x = x++ + ++x;

x will have the value 10 afterwards. I think this is because the pre-increment sets x to 5, which makes it 5+5 which evaluates to 10. Then the post-increment will update x to 6, but this value will not be used because then 10 will be assigned to x.

But when I code:

int x = 4;
x = x-- - --x;

then x will be 2 afterwards. Can anyone explain why this is the case?

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
Schweder
  • 1,464
  • 2
  • 13
  • 19
  • 4
    Great question! And we have learned never write code you have to think about what it could do, but what it would do. – RvdK Dec 20 '11 at 09:32
  • 1
    Stuff like this is why I tend to avoid ++ and -- completely. @Giorgio, I often why these were brought forward into C#. – Andy Dec 20 '11 at 18:15

6 Answers6

60

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
Jherico
  • 28,584
  • 8
  • 61
  • 87
Sebastian Piu
  • 7,838
  • 1
  • 32
  • 50
  • 6
    Thanks for your answer - i thought that post- and pre-increments are executed after / before evaluation of the complete codeline - but they are executed after / before the evaluation of each item in the expression. – Schweder Dec 20 '11 at 09:38
  • 1
    @Schweder, slight correction: the operators are executed after/before the evaluation of the variable to which they've been applied. Not each and every term in the expression. –  Dec 20 '11 at 09:48
  • 6
    @Inuyasha: Correction to your correction: the operators are *always* executed *after* the evaluation of the variable as a variable. The difference between the pre and post operators is only *the value returned*, not *the order in which the operations are performed*. – Eric Lippert Dec 20 '11 at 16:49
19

Lets have a look at the IL that gets generated from that statement

IL_0002:  ldloc.0     

Loads the value of x onto the stack. Stack => (4)

IL_0003:  dup         

Duplicates the topmost item on the stack. Stack => (4, 4)

IL_0004:  ldc.i4.1    

Push 1 onto the stack. Stack => (1, 4, 4)

IL_0005:  sub         

Subtract the two top values and push result onto the stack. Stack => (3, 4)

IL_0006:  stloc.0     

Store the topmost value of the stack back to x. Stack => (4)

IL_0007:  ldloc.0     

Load the value of x back into the stack. Stack => (3, 4)

IL_0008:  ldc.i4.1    

Load the value 1 onto the stack. Stack => (1, 3, 4)

IL_0009:  sub         

Subtract the two. Stack => (2, 4)

IL_000A:  dup         

Duplicate the top value => (2, 2, 4)

IL_000B:  stloc.0     

Store the top value back to x. Stack => (2, 4)

IL_000C:  sub      

Subtract the two top values. Stack => (2)

IL_000D:  stloc.0  

Store this value back into x. x == 2

Mongus Pong
  • 11,337
  • 9
  • 44
  • 72
9

From your comment:

I thought that post- and pre-increments are executed after / before evaluation of the complete codeline - but they are executed after / before the evaluation of each item in the expression.

Your misunderstanding is an extremely common one. Note that in some languages, like C, it is not specified when the side effect becomes visible and it is therefore legal, but not required, for your statement to be true in C.

This is not the case in C#; in C# side effects of code on the left side of an expression are always observed to happen before code on the right side executes (from a single thread; in multithreaded scenarios all bets are off.)

For a more detailed explanation of what the increment operators do in C#, see:

What is the difference between i++ and ++i?

There are a great many additional links there to articles I've written on this often-misunderstood topic.

Community
  • 1
  • 1
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
6

The most interesting thing that you'll get a completely different answer with C++.Net compiler.

int x = 4;
x = x++ + ++x; // x = 11
x = 4;
x = x-- - --x; // x = -1

Of course the difference in results is determined by different semantics - it seems normal. But despite the understanding the fact that two .net compilers don't behave in a similar manner for such basic things confuses me too.

Alex Kovanev
  • 1,858
  • 1
  • 16
  • 29
  • 2
    In C++ (not one of Microsoft's non-C++ versions of C++), modifying a variable multiple times before the end of the full expression yields undefined behavior. – Sebastian Mach Dec 20 '11 at 13:40
  • 4
    This has nothing whatsoever to do with the *parse*. It has to do with the two languages' different permitted semantics regarding sequence points. – Eric Lippert Dec 20 '11 at 16:51
3

In this example,

int x = 4;
x = x++ + ++x;

you can break it like:

x = 4++; which is = 5
x = 4 + ++5; which is 4 + 6
x = 10

Similarly,

int x = 4;
x = x-- - --x;

Here,

x = 4--; which is = 3
x = 4 - --3; which is 4 - 2
x = 2

Simply putting you can say, replace the current value of x, but for every ++ or -- add/subtract a value from x.

Azhar Khorasany
  • 2,712
  • 16
  • 20
-1

I think the explanation for the ++ + ++ case is wrong:

command...........value of x

..................undefined

int x=4 ..........4

x++...............5 (first summand is 4)

++x...............6 (second summand is 6)

x=summand1+summand2 ..4+6=10

Analogous the explanation for the -- - -- case is

command...........value of x

..................undefined

int x=4 ..........4

x--...............3 (subtactor is 4)

--x...............2 (subtrahend is 2)

x=subtractor-subtrahend ..4-2=10

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
  • I did not understand you answer at all, sorry. – Sebastian Mach Dec 20 '11 at 13:41
  • @phresnel I corrected a couple of mistakes in the answer. He's basically saying the same thing as the answer you accepted: We're actually getting 10 because we're adding 4 and 6; 2 is the difference between 4 and 2. – phoog Dec 20 '11 at 19:42