In general, consult 5/9 in the standard.
In your example, the signed value is converted to unsigned (by taking it mod UINT_MAX+1), then the subtraction is done modulo UINT_MAX+1 to give an unsigned result.
Storing this result back as a signed value to s
involves a standard integral conversion - this is in 4.7/3. If the value is in the range of signed int
then it is preserved, otherwise the value is implementation-defined. All the implementations I've ever looked at have used modulo arithmetic to push it into the range INT_MIN
to INT_MAX
, although as Krit says you might get a warning for doing this implicitly.
"Stunt" implementations that you'll probably never deal with might have different rules for unsigned->signed conversion. For example if the implementation has sign-magnitude representation of signed integers, then it's not possible to always convert by taking modulus, since there's no way to represent +/- (UNIT_MAX+1)/2
as an int.
Also relevant is 5.17/7, "The behavior of an expression of the form E1 op= E2
is equivalent to E1 = E1 op E2
except that E1
is evaluated only once". This means that in order to say that the subtraction is done in the unsigned int
type, all we need to know is that s - u
is done in unsigned int
: there's no special rule for -=
that arithmetic should be done in the type of the LHS.