C++11 §3.9.1/4, full quote:
” Unsigned integers, declared unsigned
, shall obey the laws of arithmetic modulo 2n where n is the number
of bits in the value representation of that particular size of integer.
Apart from the slightly misleading wording about “declared unsigned
” this might seem to apply that every arithmetic expression that involve only argument of some given unsigned type, will yield a result modulo 2n for that type.
However, there are no arithmetic expressions at all for unsigned types of lower conversion rank than int
: all arguments in an apparent such expression are converted up to (1)at least int
, or depending on the number ranges of the C++ implementation, up to unsigned int
.
As a result, a*b
where a
and b
are unsigned short
values, (2)can have formally Undefined Behavior. Because it's not an unsigned short
expression. It's (in practice) an int
expression.
That said, with a reasonable compiler that doesn't introduce special casing where it notices formal UB, and with in-practice 8 bit bytes and unsigned short
max value that is representable by int
, and common two's complement signed integer representation, the result, when converted back down to unsigned short
, will be as if it was modular arithmetic in the range of unsigned short
. That's because two's complement, at the machine code level, is just modular arithmetic with a range centered on 0.
(1) In practice one will usually be using an 8 bits-per-byte implementation where the maximum value of unsigned short
fits well within the int
range, so in practice we're talking about a conversion up to int
.
(2) E.g., for 16-bit unsigned short
and 32-bit int
, (216−1)2 = 232−2×216+1 > 231−1, where the last value is the maximum positive int
value.