As a follow-up to "https://stackoverflow.com/questions/33732041/why-static-castunsigned-intushrt-maxushrt-max-yields-correct-value"
I was asking myself if promoting all types (except some exceptions) with a lower rank than int
to int
to perform arithmetic operations might cause UB in some cases.
e.g.:
unsigned short a = 0xFFFF;
unsigned short b = a*a;
As unsigned short is promoted to int
for arithmetic operations this would result in:
unsigned short a = 0xFFFF;
unsigned short b = (int)a*(int)a;
As (int)0xFFFF*(int)0xFFFF
causes an overflow, and overflow of signed types is UB: Can multiplying two unsigned shorts x,y
cause undefined behaviour in the case that x*y > INT_MAX
UPDATE:
The question specifically aims at the case that int
is 32-bit and short
is 16-bit.
” 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.
When you multiply unsigned short * unsigned short
then there is an implicit conversion and the value is casted to int
in C++11. The documentation says:
Prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int). In particular, arithmetic operators do not accept types smaller than int as arguments
So it will result in an Undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With