Comment by nayuki

3 hours ago

Thank you for being one of the few people who understands that in C/C++, `unsigned OP unsigned` can have each operand be promoted to a signed integer and then have the operation overflow and cause undefined behavior.

I chose to deal with this problem by doing a "pointless" operation to force a promotion to at least unsigned int. For example:

    uint16_t x = 0xFFFF;
    uint16_t y = 0xFFFF;
    uint16_t z = (uint16_t)((x + 0U) * (y + 0U));

This piece of code will work on any machine, such as: (uint16_t = unsigned short = 16 bits, uint32_t = unsigned int = 32 bits); (uint16_t = unsigned short = unsigned int = 16 bits, uint32_t = unsigned long = 32 bits).

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?