Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does multiplying unsigned short cause undefined behaviour?

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.

like image 916
Simon Kraemer Avatar asked Nov 16 '15 09:11

Simon Kraemer


2 Answers

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.

like image 166
Cheers and hth. - Alf Avatar answered Oct 11 '22 17:10

Cheers and hth. - Alf


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.

like image 22
Rahul Tripathi Avatar answered Oct 11 '22 16:10

Rahul Tripathi