Reading ES.43: Avoid expressions with undefined order of evaluation, it states that the result of this expression
v[i] = i;
is undefined. I'm assuming that's another way to say we got undefined behavior (UB).
Reading SO posts on this topic, specifically Why is i = i 1
undefined behavior in C 11? and Undefined behavior and sequence points, I conclude that the expression should be well-defined since:
- Value computation of right operand is sequenced before value computation of left operand for assignment operator (N4835, §[expr.ass]/1.)
- Side-effect of pre-increment operator is sequenced before value computation of the preincrement (sub)expression (hopefully; don't have source for this)
meaning we do not have any side-effect unsequenced to value computation or another side-effect for the same object.
What am I missing?
Note: My question is intended for C 20. If there is any changes regarding this in previous Standards (up until C 11; so C 11, C 14 and C 17) I would like to know the changes as well. Also, I've noticed a similar post on this Why is i = v[i ] undefined?, but it's about post-increment so I didn't find an answer there.
CodePudding user response:
Value computation of right operand is sequenced before value computation of left operand for assignment operator (N4835, §[expr.ass]/1.)
Not only value computation, also side effects. This rule was however added only with C 17.
This rule alone is enough to make your expression well-defined. But even if the side effects weren't sequenced through =
, i
is defined to be identical to i =1
, and [expr.ass]/1 also says that the side effect of (compound) assignment is sequenced before its value computation, so that your second rule is true (even before C 17).
What am I missing?
The core guidelines are not purely about C 17 and later. They are warning you that this may be undefined behavior depending on standard version chosen and because it is likely to be completely silent UB, that is still dangerous. There is practically no good reason to write expressions like this. Simply separating into two statement i; v[i] = i;
takes barely any longer to write and is much easier to follow, regardless of whether v[i] = i;
also works.