- Is
x+=x*=x
undefined behavior? - Can anyone explain this rule in Order of evaluation? What is "single evaluation"? What is the opposite of "single evaluation"?
14) With respect to an indeterminately-sequenced function call, the operation of compound assignment operators, and both prefix and postfix forms of increment and decrement operators are single evaluations.

- 8,038
- 2
- 40
- 58

- 141
- 9
-
1`Is x+=x*=x undefined behavior?` Yes, no sequence point between multiple assigment (i.e., value change). – Sourav Ghosh Nov 20 '19 at 15:17
-
6Please do not provide C++ references for a C question. They're not the same language. – Andrew Henle Nov 20 '19 at 15:17
-
@SouravGhosh [I'm not so sure](https://port70.net/~nsz/c/c11/n1570.html#6.5.16.2p3): "A compound assignment of the form E1 op = E2 is equivalent to the simple assignment expression E1 = E1 op (E2)" So I read that as saying it should be evaluated as `x = x + ( x = ( x * x ) )`. I don't see any UB. – Andrew Henle Nov 20 '19 at 15:22
-
So what do we need to explain? C? or C++? What is `x`, what is the programming language?! – Antti Haapala -- Слава Україні Nov 20 '19 at 15:22
-
Yes, `x += x *= x` is equivalent to `x += (x *= x)` - since `+=` and `*=` have equal precedence and right-to-left associativity. However, that does not guarantee that `x * = x` is evaluated before the leftmost `x`. In any event, the behaviour is undefined in C, since `x` is modified twice in one statement. – Peter Nov 20 '19 at 15:22
-
1@AndrewHenle it is UB because there is multiple assignment anyway. It does not matter how you consider the grouping to be. – Antti Haapala -- Слава Україні Nov 20 '19 at 15:23
-
@AndrewHenle What should be the final value of X per yourself? Well, not what I would expect: https://ideone.com/ncXE45 :) So UB it is... – Eugene Sh. Nov 20 '19 at 15:23
-
@AnttiHaapala I'm looking for the reference now... – Andrew Henle Nov 20 '19 at 15:24
-
2@AndrewHenle the same as ever: *"Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored"* – Antti Haapala -- Слава Україні Nov 20 '19 at 15:24
-
1Clearly it's undefined. `x` is modified twice between sequence points. Why is there any doubt or debate about this? – Steve Summit Nov 20 '19 at 15:38
-
@Patrick The bottom of the page you linked has a link to its own [C version of the page](https://en.cppreference.com/w/c/language/eval_order). That might be a better choice for your question. – Blastfurnace Nov 20 '19 at 15:57
-
Well, it isn't UB in C++17... C and C++ are the same up to C11/C++11. In C++14 the C++ committee only managed to confuse themselves. C++17 contains the fix that C++14 was supposed to contain. As for C, the committee would hate to improve the language by removing well-known language flaws. – Lundin Nov 20 '19 at 15:57
-
1This really needs a language-lawyer tag. It doesn't matter if it is undefined behavior; it is an atrocity that should never be written except for the purpose of language lawyering! – William Pursell Nov 20 '19 at 16:04
-
@AnttiHaapala I'm sorry for making mistake when copying the link. It is c not c++ and thanks for correcting the link. – Patrick Nov 20 '19 at 22:21
2 Answers
x+=x*=x
has undefined behaviour because x
is assigned to twice between sequence points.
The text corresponding to 14) in C11, C17 says
A compound assignment of the form E1 op= E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.
What I believe it means is that
int x = 0;
int foo(void) {
x = 5;
return x;
}
int main(void) {
int y = foo() + (x += 2);
}
will have either the behaviour of
int main(void) {
int _tmp = x += 2;
int y = foo() + _tmp;
}
or
int main(void) {
int _tmp = foo();
int y = _tmp + (x += 2);
}
and cannot be split to for example
int main(void) {
int _tmp = x;
int _tmp2 = foo();
x = _tmp + 2;
int y = _tmp2 + x;
}
Note that this guarantee is new in C11, and it does not exist in C89, C99.

- 129,958
- 22
- 279
- 321
-
Given something like `*p += f();`, would the Standard make clear whether the call could occur between evaluation of `p` and the accesses to that lvalue? I think the C and C++ Standards would both benefit by recognizing that an lvalue used as the left operand of an assignment operator, or which has its address taken, must be "resolved" prior to the assignment or the first use of the resulting address, and by explicitly specifying how such resolution is sequenced with other parts of expression evaluation. – supercat Nov 22 '19 at 17:53
-
What about `int _tmp = x+2; int _tmp2 = foo(); x = _tmp;`? In this case, x also becomes 2. The value of `x+=2` is evaluated in a row, but not its side effect. Can this happen after C11? – imba-tjd Nov 26 '22 at 06:23
-
@supercat curious that I'd see this only *now*. Looks like the standard suggests *in the foot note* that `p` can be evaluated *before* to get the pointer value, only dereferencing would happen in the "single operation" http://port70.net/~nsz/c/c11/n1570.html#note113 – Antti Haapala -- Слава Україні Dec 04 '22 at 09:15
-
@AnttiHaapala--СлаваУкраїні: I think that part of the Standard is only applicable when using atomic types. – supercat Dec 04 '22 at 21:24
1) Yes.
C17 6.5.16 Assignment operators, §3
The evaluations of the operands are unsequenced.
Which makes it UB because of C17 6.5 §2
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
Every assignment is a side effect. C99 had the same rule but it was much easier to understand:
C99 6.5 §2
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.
2) All the text with C11 sequencing changes is rather confusing to read. They use terms that aren't formally defined anywhere, such as "single evaluation".
The normative text is C17 6.5.15.2 §3
A compound assignment of the form E1 op= E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.
I suppose that this simply means that an operation like int x;
... x += 1
should result in machine code like:
- Store 1 in register
- Add x to register
- Write register to x
Otherwise, suppose something gets sequences in between those operations that updates x
. But compound assignment isn't atomic no matter, so I don't quite understand what the standard is after here.

- 195,001
- 40
- 254
- 396
-
I guess what it says is that `z = foo() + (x += y)` `foo` will either see `x` changed already, at which point `foo()` by changing global `x` cannot affect the value of the evaluation `x += y`, or `foo()` executes completely before and `x += y` is evaluated. – Antti Haapala -- Слава Україні Nov 20 '19 at 16:52
-
I think the compound assignment is atomic in this context and it can't be interleaved with other functions. – Patrick Nov 20 '19 at 22:45