Right-associative (*, ++)

My source tells me that the * operator (i.e. the dereference operator) and the ++ operator have the same precedence, and that they are also both right-associative. Therefore, it tells me,

*iterator++

is equivalent to writing

*(iterator++).

Now I'm confused, as I thought that when an expression contains brackets, whatever is inside those brackets should be evaluated first. Therefore, with *(iterator++) you should first increment the iterator THEN dereference it. However, my source is then telling me that

*iterator++ = *iterator2++

is equivalent to

{ *iterator = *iterator2; ++iterator; ++iterator2 }

which shows that first the iterator is being dereferenced, THEN incrememted, contrary to what it first said. What is going on?

Suffix increment [iterator++] has a higher precedence (and is left associative) than Indirection (dereference) [*].
with *(iterator++) you should first increment the iterator THEN dereference it.

The return value of post-increment is the nameless copy of the non-incremented argument. That is what is returned from the parenthesized expression, regardless of when the increment occurs, and that is what operator* gets to work with.

However, there's another thing I'd like to point out.

I thought that when an expression contains brackets, whatever is inside those brackets should be evaluated first.

No, it only means it is *parsed* first. Precedence is not evaluation order, precedence is grammar. It is the set of rules by which an expression is parsed into the tree form

Your expression is parsed into this tree:

                ,- increment
               /
iterator ---> op++(post) --->  op*    ,- store
                                  \  /                      
                ,- increment       op(=) ---> (discard)
               /                  /
iterator2 ---> op++(post) ---> op*


The compiler has (almost) free reign on how to evaluate this tree. Depth-first, breadth-first, top first, bottom first, or in any other manner. Your compiler apparently went (how did it "tell" you anyway?) copy, copy, op*, op*, op=, store, top increment, bottom increment. Another compiler could go top copy, top op*, top increment, bottom copy, bottom op*, bottom increment, op=, store. Another compiler could go top copy, bottom copy, bottom op*, top increment, top op*, op=, store, bottom increment. It could even interleave the individual CPU instructions working on unrelated data, to improve pipelining (but only if the arguments are scalars, e.g. typedefed pointers. There is much less leeway when those operators are user-defined functions)
Last edited on
Always use parenthesis, even if you're expecting defined behaviour.
@EssGeEich
Always use parenthesis, even if you're expecting defined behaviour.


There is no need always to use parentheses and the expression

*iterator++ = *iterator2++;

is clear enough.
I would use parenthesis to make sure it's gonna do that job in the right way. Happy 1024 posts anyways.
Topic archived. No new replies allowed.