Confuse regarding operator precedence

I am trying to understand how increment (and decrement) operator works based on where they are placed. In the following code, in the end y will contain 3 and x contain 4. But the suffix ++ has higher precedence than assignment operator =. Shouldn't this mean the x++ part be evaluated first to give x=4, and then the assignment gives y=x=4?

1
2
  x = 3;
  y = x++;
Last edited on
Precedence doesn't affect what post-increment does. By definition, although it increments the variable, it evaluates to the value of the variable before the increment. Written as a function:

1
2
3
4
5
6
7
int postinc(int &x) {
    int ret = x;
    x = x + 1;
    return ret;  // return the value before the increment
}

y = postinc(x);   // y gets x's old value 

Last edited on
So the ++ and -- operators are exception to the precedence rule?
No.

The precedence rules describe how expressions are grouped together.

By knowing that ++ has higher precedence than = we can conclude that line 2 should be interpreted as y = (x++);

If instead = had higher priority than ++ the expression would have been interpreted as (y = x)++;

Order of evaluation is a different concept with its own set of rules.

https://en.cppreference.com/w/cpp/language/operator_precedence
https://en.cppreference.com/w/cpp/language/eval_order
Last edited on
So the ++ and -- operators are exception to the precedence rule?

No. Not at all. Precedence is just about the default grouping of subexpressions. No matter how they are grouped, post-increment does the same thing. x++ always equals the value of x before the increment. The fact that x is incremented is a side-effect and not part of the expression value at all.
Last edited on
just need to be a little careful of the slight differences when using these operators in for and while loops. Suppose I had

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

void Rev(string& s)
{
    int i = 0;
    int j = s.size()-1;
    while (i < j)
        swap(s[i++], s[j--]);
}

int main() 
{
    string s("Hello World!");
    cout << s << endl;
    Rev(s);
    cout << s << endl;

    return 0;
}


Hello World!
!dlroW olleH


It would've been a mistake, without other changes, to try
1
2
    while (i++ < j--)
        swap(s[i], s[j]);

because what happens is
1. i<j evaluated
2. i++ happens. j-- happens
3. NOW the body of the loop occurs, and already we're off by an index when we didn't want to be.

Edit: example with for.
Similarly, this would be a mistake for the same reason
1
2
    for ( ; i++ < j--; )
        swap(s[i], s[j]);


But this is fine, since the third part of a for loop is evaluated after the body
1
2
    for ( ; i<j; i++, j--)
        swap(s[i], s[j]);
Last edited on
icy1 reminded me of an idiom that I like. When counting downwards, instead of doing this:
 
for (int i = 10; i >= 0; i--) // stops when i goes negative 


You can do this:
 
for (int i = 10; i-- > 0; )  // stops when i WAS zero (on last iteration) 


And it's particularly good (necessary, really) if the index is unsigned, since in that case it can never go negative:
 
for (size_t i = 10; i-- > 0; )

Last edited on
@tpb Well, there's a difference between your first example and the other two --
First goes from 10 to 0 , inclusive

But this
for (int i = 10; i-- > 0; ) // stops when i WAS zero (on last iteration)
effectively begins its body statements at i=9 down to 0. If i was initialized to something.size() this is fine because we usually subtract one from the end anyway.

Edit: if you wanted to go from 9 to 0, (or from something.size()-1 to 0), I like this one:
1
2
3
4
int i = 10;
while (i--)
{
}
Last edited on
@icy1, You're right. I screwed up. I meant the first example to start at size-1 (9 in that example).
Thank you for all the examples, they help me understand better this prefix and postfix increment operators thing. If my understanding is correct, any expression

statement;

containing post-incremented operator will be evaluated until the semicolon using the unincremented value, afterwards the variable followed by the post-increment is affected by this operator.
afterwards the variable followed by the post-increment is affected by this operator

Not quite. Time has nothing to do with it. It's not that "afterwards the variable ... is affected". It could be the case that the variable is incremented before any other part of the statement is executed. It's just that the old value is used in the the expression. It's as simple as that. For instance, that's how the example function I wrote above works. It changes the value of the variable, but returns the old value.

Note that his makes a statement like the following problematic:

 
y = x++ + x;

What value would the second x have in the expression? In fact, such a statement is an example of what is called "undefined behavior", and it's a mistake to write such a thing. You are not supposed to use the value of a variable modified by a side-effect more than once in a statement.
That is interesting. I ran it with x=5 and I got y=11. But as soon as I swapped the order of the RHS so that
y = x + x++;
I got y=10. This means in the first case, the new x value was used whereas in the second case the old one was used. In either case I got warning warning: unsequenced modification and access to 'x' [-Wunsequenced].
Anyway, this makes it as if addition operation is not always commutative in C++.
Topic archived. No new replies allowed.