I have seen a similar question but mine is specifically referring to the augmented assignment operators such as +=
, -=
, etc. How exactly do the those operators work when I have the following?
extern signed s;
extern unsigned u;
s += u;
Will this be equivalent to this?
s = (signed)((unsigned)s+u);
More specifically would this invoke undefined behavior due to signed integer overflow?
signed s = INT_MAX;
unsigned u = 1;
s += u;
I am aware that when using the normal arithmetic operators, the unsigned type usually dominates. However, I am not sure if this holds true for the augmented assignment operators.
This:
s += u;
Is the same as this:
s = s + u;
As per section 6.5.16.2p3 of the C standard:
A compound assignment of the form
E1 op = E2
is equivalent to the simple assignment expressionE1 = E1 op (E2)
, except that the lvalueE1
is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation
So first s + u
is evaluated. This causes s
to be converted to type unsigned
as per the usual arithmetic conversions, and the result is unsigned. Then this result is assigned back to s
which undergoes a conversion from unsigned
to signed
.
So in this particular case:
signed s = INT_MAX;
unsigned u = 1;
s += u;
The value of s
is converted to unsigned
and 1 is added to it, resulting in an unsigned value of INT_MAX + 1
. This value is then converted to signed
, which undergoes an implementation defined conversion due to the value being out of range as per section 6.3.1.3p3:
1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
So the above does not have undefined behavior, but it does have implementation defined behavior.