C++: (un)signed overflow
Yet another way to fail somebody on an interview:
int main() {
uint16_t a = 0xEDCB;
uint16_t b = 0xF012;
uint16_t c = a * b;
printf("0x%.4X * 0x%.4X = 0x%.4X\n", a, b, c);
}
This little snippet actually has UB¹.
Or not. But probably does.
Technically, it depends on your platform. If you’re somehow on DOS and have 16-bit int you’re fine. But all modern platforms have 32-bit int and it’s a problem.
See, neither C nor C++ support arithmetic on types smaller than int. So both a and b are promoted to ints before multiplication. This step is lossless as int can hold all their values. But it can’t hold the product, and signed overflow is UB!
GCC can actually catch this with -fsanitize=undefined, with a typically helpful message:
ushort-overflow.cxx:7:22: runtime error: signed integer overflow: 60875 * 61458 cannot be represented in type 'int'
Of course being a C++ programmer you already know that multiplying two unit16_ts results in an int so it only has to report that somebody has passed out-of-range arguments to your code.
printf
By the way that’s not the only UB in the code. In printf, %X requires an unsigned int argument. Passing an int instead is an UB, and that’s exactly the type uint16_t gets promoted to (again, unless int is only 16 bits). GCC doesn’t catch this one (though it might just treat the types as compatible instead).
¹ “Undefined Behavior”, standardese for “totally and absolutely invalid”. Typically treated as unreachable; the compiler can actually remove the entire branch that contains UB. And often does.