Question

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?

Was it helpful?

Solution 2

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.

OTHER TIPS

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

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.

Make 'auto' into a signed type and you will be fine:

long test = smallValue * value * anotherSmallValue;

Operating with mixed types is always prone to such errors. I advise you to use a single type for arithmetic operations

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top