3

I don't understand why in C#, ++x - --x is 1 for every value of x.

int x = 0;

Console.WriteLine(++x - --x); // gives 1

I believe the answer should be 0, as variable x involves both sides. And x is incremented and decrimented before the processing of substraction. The same equation in C++ returns 0, that make sense to me.

Can anyone give a clue what's actually happening here?

Salar Askar
  • 126
  • 6
  • 11
    C# or C++? In C++ this is undefined behaviour, so that it returns `0` means nothing. It could return . – tadman Nov 06 '20 at 08:30
  • 4
    https://stackoverflow.com/questions/949433/why-are-these-constructs-using-pre-and-post-increment-undefined-behavior. I don't know if it is undefined behaviour in C#, but code like this is nonsense anyway. – Jabberwocky Nov 06 '20 at 08:33
  • 5
    "*And x is incremented and decrimented before the processing of substraction*" this is your assumption, turns out its wrong though – TheGeneral Nov 06 '20 at 08:35
  • 1
    Those kinds of questions have been answered a thousand times on this site alone. The actual answer should be: Do not _ever_ write such code. It is a stupid idea to do so, because of exactly that kind of confusion it causes. C++ does the right thing by making it a garbage statement, therefore discouraging its use. Separate your code into lines you can understand and you'll be much happier. – stefan Nov 06 '20 at 08:35
  • 1
    If you look at the IL you will see clearly, https://sharplab.io/#v2:EYLgHgbALANALiAlgGwD4AEBMBGAsAKHQGYACLEgYRIG8CT6zT0oSBZACgEoa6G+A3AIYAnEmBIBeEgAYA3Lz7102AJzsA1OvEBaEtu1hO8/HwC+BU0A – TheGeneral Nov 06 '20 at 08:36
  • 2
    Just to be clear, @TheGeneral, that's not *always* a reliable indicator. I could look at the machine code generated by `gcc` and still not be any wiser as to whether it was guaranteed. In this case, it is, but that's more down to the language spec than to the underlying IL. – paxdiablo Nov 06 '20 at 09:09
  • @paxdiablo though I agree, in this case it is easy to see, it loads , pushes 1, adds, copies, pushes 1, subtracts copies pops and subtracts. Though the IL was pointless, as the result speaks for itself – TheGeneral Nov 06 '20 at 09:29

1 Answers1

8

This is actually undefined behaviour in C and C++. For example, C states that reading and modifying an object without an intervening sequence point is undefined.

However, C# locks down the behaviour so that behaviour is defined. From the online docs:

Unrelated to operator precedence and associativity, operands in an expression are evaluated from left to right. The following examples demonstrate the order in which operators and operands are evaluated:

OPERAND EVALUATION
Expression Order of evaluation
a + b a, b, +
a + b * c a, b, c, *, +
a / b + c * d a, b, /, c, d, *, +
a / (b + c) * d a, b, c, +, /, d, *

And, from the operator precedence table, you can see that ++x (unary category) has a higher precedence than x + y (additive category).

In your case, the sub-expression ++x is evaluated first and results in x being pre-incremented so the value of that sub-expression is the original x plus one.

Then the sub-expression --x is evaluated and results in x (already incremented from the previous step) being pre-decremented so the value of that sub-expression is the original x.

And, since x + 1 - x == 1 for all but the darkest corners of the math universe, the result is always one. I still wouldn't do something like this, but it at least is well defined.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953