These are fine:
y = ++(int){++x};
y = (int){x++}++;
As no object is being read or written more than once, specifically x
, y
, and the unnamed compound literals. Modifying the compound literal is also not a problem because (in this case) it has automatic storage duration and so its lifetime is that of the enclosing block, even though it will be unaccessible due to its address not being taken.
In contrast these trigger undefined behavior:
x = ++(int){++x};
x = (int){x++}++;
Because x
is modified more than once without a sequence point, as use of a compound literal does not introduce a sequence point.
Section 6.8p4 of the C standard states the following (not the bolded part):
A full expression is an expression that is not part of another
expression or of a declarator. Each of the following is a full
expression: an initializer that is not part of a compound literal; the
expression in an expression statement; the controlling expression of a
selection statement (if
or switch
); the controlling expression of a
while
or do
statement; each of the (optional) expressions of a for
statement; the (optional) expression in a return
statement. There is a
sequence point between the evaluation of a full expression and the
evaluation of the next full expression to be evaluated.
In the example above, because ++x
is part of the initializer of a compound literal, it does not qualify as a full expression and therefore there is no sequence point introduced by the compound literal.
x = ++(int) { ++x };
gets a warning from clang-cl: warning : multiple unsequenced modifications to 'x' [-Wunsequenced]. But not fory = ++(int) { ++x };
. – Hurffx = (int){x++}++;
is unspecified behavior, sincex
is modified twice (the inner++
and the outer assignment). It would be the same withx = x++;
– Couscousx = (int) { ++x };
. – Hurffx
: One with the=
operator and one with the++
operator. – Couscousx
from an expression that modifiesx
. – Couscous