Reputation: 782
Working through a bug today we realized that we were bit by an implicit type conversion.
int64_t result = intA * intB;
In the case where intA and intB are both positive int
, they can overflow at values > 2^31.
I would expect a similar issue with the following code:
int64_t result = (intA * intB) - int64A
But it seems in practice as if we aren't overflowing on the result of intA * intB
.
Is that right? If so, why? I read through some of the implicit type conversion rules for C++ to try and understand if it might be because the int64A operand is 64-bits but couldn't find anything conclusive.
Upvotes: 2
Views: 70
Reputation: 213298
I am assuming 32-bit int
here.
C++ makes this complicated with the addition of user-defined conversions, but let's assume that user-defined conversions aren't being considered here.
For most arithmetic operations on integers (e.g. not shifts), you get the following conversions (this is from memory...):
Each operand is converted to int
if it is narrower1 than int
, and all values of its type can be represented by int
.
Each operand is then converted to unsigned
if it is narrower than unsigned
.
Each operand is then converted to the wider type of the two operand types, if one of the types is wider.
If they are the same width, but one is unsigned, then the unsigned type is chosen.
The first two steps are called "integer promotion" and the second two steps are part of the "usual arithmetic conversions".
So, if you want to do 64-bit multiplication,
int x, y;
// Always done with int
int r = x * y; // 32-bit
// These are always done with int64_t
int64_t r = (int64_t)x * y;
int64_t r = x * (int64_t)y;
int64_t r = (int64_t)x * (int64_t)y;
// This is a 32-bit multiplication, you probably don't want this...
// The RESULT is converted to 64 bit
int64_t r = x * y; // 32-bit
// Same thing...
int64_t r = (int64_t)(x * y); // 32-bit
The subtraction happens to the multiplication result, so if the multiplication result is 64-bit, then the subtraction will be done with 64 bits.
HOWEVER: As soon as you overflow with signed integer arithmetic, the results are undefined! This means that if x * y
overflows, the compiler is allowed to do anything it wants. Maybe it gives you the 64-bit result. Maybe it crashes. Maybe it formats your hard drive. Maybe things behave oddly in your program.
In practice this is "bounded undefined behavior" so it probably will just cause you to scratch your head and curse rather than crash your program outright.
1: "Narrower" is not technically the term used in the standard.
Upvotes: 1