Reputation: 14052
For the following code I get an overflow but sadly I cannot seem to understand why.
std::int8_t smallValue = -1;
unsigned int value = 500;
std::uint8_t anotherSmallValue = 1;
auto test = smallValue * value * anotherSmallValue;
Afterwards test
is a quite large value.
Could someone explain, what happens here?
Upvotes: 1
Views: 174
Reputation: 13908
When the compiler sees smallValue * value
, it must decide what the data type of the result is going to be, given the input data types signed
(8 bits) and unsigned int
(usually, either 16 or 32 bits). The rules of C++ state that in this situation, the result will be unsigned. Therefore, the value of smallValue * value
cannot be -500
, as you are expecting; instead, the value -500
is interpreted as a POSITIVE number.
Furthermore, you are here multiplying an 8-bit value by a value that is typically either 16- or 32-bit. The rules of C++ in this scenario state that the smaller-storage value will first be cast to the same size as the larger; so in this case the result of smallValue * value
will indeed be large enough to store a number of magnitude 500
.
Proceeding to multiply by the unsigned quantity anotherSmallValue
(=1) results in another unsigned
with the same value.
Because you are using auto
, the return type is therefore deduced to be unsigned
.
Simply by casting back to a signed
(by, for example, defining the value test
as an int
, rather than an auto
, will in turn typically cast the result of the entire operation back to a signed
value, without changing the bits internally; this will then properly display -500
, as you expect; however, as other posters have noted, this is rather dangerous in theory because it's not techincally guaranteed to work, although it usually will work this way with today's compilers.
Upvotes: 5
Reputation: 254431
You will get the same result with just the first two variables (smallValue * value
).
First, integral promotions are applied to both values: int8_t
becomes int
, and unsigned int
remains as it is.
Then this rule from C++11 5/9 is applied to determine the result type:
Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.
So -1
must be converted to unsigned int
using modular arithmetic, giving a large positive number. Multiplying by 500 will overflow (again using modular arithmetic), giving a different large number.
Upvotes: 2
Reputation: 7919
Operating with mixed types is always prone to such errors. I advise you to use a single type for arithmetic operations
Upvotes: 1
Reputation: 55887
result type will be unsigned int
test here. smallValue * value
smallValue
will be casted to unsigned, so this expression is (unsigned)-1 * 500
. However, if you compile this code with -Wsign-conversion
- compiler tells you, that you do bad things. link
Upvotes: 6
Reputation: 567
Make 'auto' into a signed type and you will be fine:
long test = smallValue * value * anotherSmallValue;
Upvotes: 1