15,117,318 members
See more:
int a = 3;
int b = 5;
int c = 40;
int d = c-- - b * a;
Console.WriteLine(\$"a={a}, b={b} c={c} d={d}");

an order of "c-- - b * a" expression handling expected like this :

39 15
int d = (c--)-(b*a); == 24? of cource not! d=25!

because in fact an execution order is following:

int d = c-(b*a); and c-- is postdecrement operation and lost somehow

so thiese expressons are equal

int d = c-(b*a) and
int d = (c--)-(b*a)

Could somebody explain how?

and moreover!

if you'll try to use QuickWatch on (c-- - b * a), it fulfilles the procedure in the background and changes the c so when you try to use it again, the result will be 24! because the c has being changed.
I believe it is not correct
because QuickWatch should execute the expression, but in the different place somewhere and shouldn't change the variable.

What I have tried:

simple arythmetic question C#.
Posted
Updated 3-Feb-20 4:10am
Richard Deeming 4-Apr-19 12:01pm

Any code which tries to be "clever" by mixing an increment/decrement operator into a larger set of operations in a single statement should be thrown out. There's absolutely no benefit to doing it; it just makes your code harder to read. Even developers with lots of experience of "clever" code will have to stop and think to work out what it's supposed to be doing.

## Solution 1

They aren't the same. `c--` is a postfix operator which changes `c` after it's been used.
You need to be very careful when using these, as the results you get may not be what you expected. See here: Why does x = ++x + x++ give me the wrong answer?[^]

Quote:
Thank you so much! I've read an article and found the "Precedence and Order of Evaluation" from MSDN.
For the moment the precedence of operators doesn't answer the question "why"
for example
int a = 5;
int b = 3;
int i = 10;
int x = (i++) + a * b;
logically (if we agree with precedence) i should be 11 (!) and x = 26, not 25, because i++ is placed in brackets.
but the ++ operator is still omit eventually, no matter on evaluation direction

No, you are wrong.
C#
`int x = i++ + a * b;`
Is using a post fix increment, which says, "use the current value of `i` and then add one to `i`"
If you write it long hand, you get this:
C#
```int i2 = i;
i += 1;
x = i2 + a * b;```
which is:
C#
`25 == 10 + 3 * 5;`
That's why mixing auto increment and decrement operators in the same expression is so fraught: there are no universal rules to say exactly when the increment should be done.
Think of this, assuming i is 10
C#
`x = i++ + i;`
What is the value of x?
20?
21?
22?

The "right" answer is 21, and i ends up as 11.
C#
```int i2 = i;
i += 1;
x = i2 + i;```
But ... it could easily be 20 if strictly evaluated from right to left:
C#
```x = i + i;
i += 1;```
v2
[no name] 2-Apr-19 4:18am

Hi!
put thiese two expressions in c# and execute.
The result will be equal
OriginalGriff 2-Apr-19 5:20am

The result in "d" will be the same, which is the whole point - but teh value in "c" will not!
A post decrement in the middle of an expression is perfectly legal - and even sometimes wanted. It has a "side effect" that c is decremented, but it's perfectly legal and will work.
There is no warning, because it does what it is expected and designed to do!
[no name] 2-Apr-19 5:30am

the question was not about the syntax or uderstanding of an operation execution.
I meant the following:
(look at Solution_2 log)

"look, you should agree, this is not normal situation
int d = c--; // the "c--" is in the end of expression. I agree when the expression is closed after this, the postdecrement operation works as expected and in this case "d==c"

int d = c-- - b * a; //but in this case "c--" is in the middle of an expression and apparently should be executed totally to return the value to the expression it participates

The question is in evidence of an execution
OriginalGriff 2-Apr-19 5:50am

No, you don't understand. It's a perfectly normal situation.

Pre- and post-fix operators can be used on any lvalue at any point in an expression, they aren't fixed to the "end" of an expression (particularly since many compilers evaluate expressions right to left not left to right, when the order isn't important)

Doesn't matter if you don't "think they should" - they can, just like any other unary operator. Or are you suggesting that "a * -b * c" shouldn't be allowed as well? :laugh:

And the real problem is that it is a "side effect" operator, so you shouldn't write complicated expressions using them. But there is nothing stopping you doing that (other than the ultimate results are not defined in many languages and may change without notice).
[no name] 2-Apr-19 7:12am

Oh! And That Is quite interesting:
"particularly since many compilers evaluate expressions right to left not left to right, when the order isn't important"
I consider this answer "why" for me!
I did'n know that.

Thank you!
OriginalGriff 2-Apr-19 7:23am

You're welcome - it's explained in the link I gave you. Search for "Precedence and Order of Evaluation" and you'll see it.
[no name] 2-Apr-19 8:52am

Thank you so much! I've read an article and found the "Precedence and Order of Evaluation" from MSDN.
For the moment the precedence of operators doesn't answer the question "why"
for example
int a = 5;
int b = 3;
int i = 10;
int x = (i++) + a * b;
logically (if we agree with precedence) i should be 11 (!) and x = 26, not 25, because i++ is placed in brackets.
but the ++ operator is still omit eventually (not omit of cource but executed after the expression), no matter on evaluation direction
OriginalGriff 2-Apr-19 9:18am

[no name] 2-Apr-19 9:40am

>>No, you are wrong

Oh, really?!

int x = i++ + a * b;

Haven't you forgot the brackets?
Shouldn't it be like that:

int x=(i++) + a * b;

in my beliefe in this case it would be:

i += 1;
x = i + a * b;

because the brackets are in main precedence... ?

May be (and I'm sure) you're right because I can see that in C# compiler x==25!
But why?!
OriginalGriff 2-Apr-19 9:57am

The brackets don't matter - they only affect operator precedence, not evaluation order.
Remember: "Only the sequential-evaluation (,), logical-AND (&&), logical-OR (||), conditional-expression (? :), and function-call operators constitute sequence points and therefore guarantee a particular order of evaluation for their operands."
They act as a sequence point only within the brackets.
Think about it: 2 + 3 is the same as 3 + 2, yes? That's fundamental to math (and called Associativity you will remember from childhood).
So when you write x = (y) + (z) the compiler is at liberty to evaluate (y) or (z) first because it doesn't matter to the result of the addition as long as y and z are both fully evaluated before the addition. Same goes for multiplication!
If you write x = (y + z) + a then you are saying "add y and z, then add a, but the compiler can ignore the brackets because they don't change anything.
If you write x = func(y + z) + a then the function brackets act as a sequence point and tell the compiler that y, z, and y + z must all be fully evaluated before you call func, but even that has no problem evaluating "a" first (just because it feels like it) because it has "no effect on the result"

Only a very few operators establish an evaluation sequence: && and || because the specification lays down the law: "the left hand side of &&, ||, and ? must be evaluated before the right hand side"
That law does not exist for +, -, * , or /

Do not confuse precedence with evaluation order, they are not the same thing (or even related!)
[no name] 2-Apr-19 10:03am

Yup!
I'm trying to explore the ILDasm and I can see the compiler totally ignores the brackets - the listings are completely the same with brackets or without

"If you write x = func(y + z) + a then the function brackets act as a sequence point and tell the compiler that y, z, and y + z must all be fully evaluated before you call func, but even that has no problem evaluating "a" first (just because it feels like it) because it has "no effect on the result"

but if it so, the compiler should fully(!) evaluate the func(I++) first and than the rest of expression.
But obviously it doesn't
OriginalGriff 2-Apr-19 10:25am

Why? It has no effect on the result.
If funcA(...) + funcB(...) returns 123, what does it matter that funcA returns 100 and funcB returns 23? The addition operator doesn't care because addition is associative, and it can be written funcB(...) + funcA(...) and give the same result.

And so it's up to the compiler to do exactly what is convenient for it - which may not be what you think. Worse, the optimization phase of release compilation can *change that order* because it can "see" common expressions that it will only work out once, or reorder the whole expression in order to keep everything in a limited set of machine registers. You have no control over that, and that's why if you want to do something that relies on evaluation order you have to break it into separate lines to force the compiler to consider sequence points. And that's why you have to be very careful with "side effect" operations (particularly in property getters) or things can get very confusing, very quickly.

You are still confusing precedence with order, and they still aren't the same thing!
[no name] 2-Apr-19 10:53am

>>You are still confusing precedence with order, and they still aren't the same thing!
I doubt...
I believe we are talking about the different things.

I++ - is the bunch of procedures (placing in stack, incrementing, adding and etc.) right?
"function brackets act as a sequence point and tell the compiler that y, z, and y + z must all be fully evaluated before you call func"

That mean, all the procedures of this bunch have to be evaluated and the stack should be restored.
So the ++ - is not an ephemeral thing, is the procedure which has to return the result (in this case)

int i = 10;
int x = (i++) +1;

as you can see there are no any other "i" out of the brackets.
what order or precedence we discuss here?
OriginalGriff 2-Apr-19 11:01am

No, it's a unary operator that has a side effect.
you can think of pre- and post-fix increment as functions:

public static int PlusPlusPrefix(ref int x)
{
x += 1;
return x;
}
public static int PlusPlusSuffix(ref int x)
{
int y = x;
x += 1;
return y;
}

And you might see what they do. (But ... don't rely on it, the compiler does not have to treat it like that - and not all compilers do!)
[no name] 2-Apr-19 11:13am

>>No, it's a unary operator that has a side effect.
from the ILDasm perspective it's not.
So how does it come an increment result is placed in the different stack place?
... hmm..
I should explore the ILDasm of ++I...

## Solution 2

As you are stating yourself, you are using a postdecrement - so the value of c will change after it is used in your expression.

So
`d=(c--)-(b*a);`
is identical to:
`d=c-b*a; c=c-1;`
Just like
`d=(--c)-(b*a);`
is identical to
`c=c-1;d=c-b*a;`
It only gets really fun when you have multiple of them operating on one variable in one statement. Fun to play with, but never used in production code so personally I just forgot how that works.
[no name] 2-Apr-19 4:15am

Hi!
An explanation is clear.
Asking my question, I meant the operation in this case is not obvious.
It should be the warning mechanism in c# to make is more obvious
lmoelleb 2-Apr-19 4:19am

The operation is doing exactly what this operation has been doing for many decades across multiple languages - so what exactly should the warning be? Something like "If you do not know how this operation works it might give a different result than you expect"... but that goes for everything. :)
[no name] 2-Apr-19 4:32am

look, you should agree, this is not normal situation
int d = c--; // the "c--" is in the end of expression. I agree when the expression is closed after this, the postdecrement operation works as expected.
int d = c-- - b * a; //but in this case "c--" is in the middle of an expression and apparently should be executed to return the value to the expression it participates

.But still.. You right "this operation has been doing for many decades across multiple languages"
lmoelleb 2-Apr-19 4:37am

Personally I prefer avoiding the style, but I would not go so far as saying it is not normal, nor that it should be avoided in all cases. Maybe you can find (or write) a code analyzer if you prefer avoiding it? That way you will get a warning.
[no name] 2-Apr-19 4:40am

See, "Personally I prefer avoiding the style" - that is what I meant.
lmoelleb 2-Apr-19 4:42am

I do not consider my personal preference to be the definition of "normal". :D
But as mentioned - if you really want a warning here, that would be something for a code analyzer, not the core compiler.
[no name] 2-Apr-19 4:44am

Ahh... let's consider this just like exchanging of thaughts

## Solution 3

Quote:
I believe it is not correct
Your belief is wrong. See, for instance: Increment and decrement operators - Wikipedia[^].

## Solution 4

Interesting. I've never tried a question like this.

This is only a shot in the dark, but do you think the program is reading
"(C--) - (a*b)"
as
"(C(-1)(-1)) - (a*b)"?

I know it's a stretch, but if there's two negatives right next to an int, perhaps they're both turned into (-1)? If that's true, then putting them together multiplies into a multiple of +1:

d = (c--) - (a*b)
d = (c(-1)(-1)) - (3*5)
d = (c(1)) - (15)
d = 40 - 15
d = 25
Richard Deeming 3-Feb-20 10:20am

That's not what's happening. Have a read of the previous solutions, which explain what the problem is.
Jay-Mickey 4-Feb-20 12:02pm

Ah, I see now.