4 ms·
> Do you know that in MSVC uint16_t(50000) + uin16_t(50000) == -1794967296? Do you know why? Yeah, that’s what I thought. I was very confused by this claim bef
by comex 4y ago
> Do you know that in MSVC uint16_t(50000) + uin16_t(50000) == -1794967296? Do you know why? Yeah, that’s what I thought.
I was very confused by this claim before I realized it should be *, not +.
Either way, the operands are promoted to int before performing the addition or multiplication. But with addition, this is not too surprising, as you just get the mathematically correct result 100000. With multiplication, you get 2500000000, which is too large for a 32-bit signed integer. This is undefined behavior, but in practice it often results in wrapping, which is where you get -1794967296.
- ynik 4y agoImportant to note: this is dependent on the implementation-specific sizeof(int). So while on most architectures uint16_t is the unsigned type that cannot be safely multiplied; on others uint8_t or uint32_t might be unsafe to multiply. As a result, it is nearly impossible to write platform-independent code that does something like hashing (where wraparound is intended) while also producing consistent results across platforms. If course in reality, it's the other way around: 64-bit platforms were forced to define `int` as a 32-bit integer, because otherwise they wouldn't be able to run any existing code. C23 finally fixes this by introducing new fixed-size integer types _BitInt(N) that don't suffer from this numeric promotion mess. But of course the typedefs everyone is using will have to stay broken.