Assume p
is a integer pointer and i
is an integer:
*p++
gives an integer value corresponding to p
The result of post-increment is an rvalue. You're not allowed to modify it. ++i++
attempts to modify that rvalue, which the compiler rejects.
p++ produces an rvalue, but it's of pointer type. You're not allowed to modify it, but you are allowed to dereference it. *p++
dereferences that rvalue. This gives you the value it points at, as an lvalue. The pre-increment then modifies the lvalue it points at, not the rvalue that was produced by the post-increment.
Edit: I should probably also add one more point: even if ++i++
was allowed by the compiler, the result would be undefined behavior, because it attempts to modify i
twice without an intervening sequence point. In the case of ++*p++
, that doesn't happen either -- the post increment modifies the pointer itself, while the pre-increment modifies what the pointer pointed at (before it was incremented). Since we're modifying two entirely different locations, the result in not undefined behavior.
If you wanted to badly enough, you could still get undefined behavior by initializing the pointer to point at itself, in which case both increments would attempt to modify the pointer. The committee didn't work very hard at preventing this, probably because only the truly pedantic would be at all likely to even think of such an insane thing.
Bottom line: in this case, the compiler is mostly trying to protect you from yourself, though you can still shoot yourself in the foot if you try hard enough.
++i++
is decomposed as following:
i++
++(result)
Problem: i++
returns a rvalue, ie a 'temporary' value, not incrementable. This is because i++
returns i
before incrementing it.