But the result is 1, whether you calculate it as 16-by-16 unsigned multiplication (you get 0xFFFE0001 truncated down to 1), or 32-by-32 signed (you multiply -1 by -1 and get 1, with no overflow).

> 32-by-32 signed (you multiply -1 by -1 and get 1, with no overflow)

Wrong. You mentally casted each operand to int16_t before subsequently casting to int32_t. The first step is unjustified.

The correct calculation according to the C standard is: (int32_t)0xFFFF * (int32_t)0xFFFF, which definitely overflows.

> You mentally casted each operand to int16_t before subsequently casting to int32_t. The first step is unjustified.

That's horrifying. Why were unsigned shorts made to convert to signed ints by zero-extension, again?

One reason is that the language didn't originally intend for UB to be so broad. They probably expected that each value would be loaded into an int-sized register, and the calculation would then be performed on two int-sized registers with overflow handled in a platform-dependent but generally sane manner (not time travel).

Because the language rules say so, and I'm not the one who made the rules. https://en.cppreference.com/c/language/conversion#Integer_pr...

> Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of int or of {a bit-field of type _Bool(until C23)/bool(since C23), int, signed int, unsigned int}, to the value of type int or unsigned int.

> If int can represent the entire range of values of the original type (or the range of values of the original bit-field), the value is converted to type int. Otherwise the value is converted to unsigned int.

The fact that the C/C++ integer conversion rules have these unintuitive footguns is why I made it a talking point.