C++ Arithmetic With Mixed Integral Types That Causes Overflow
-
21-12-2019 - |
Question
I have done some tests in VC++2010 mixing operands of different sizes that cause overflow in add operation:
int _tmain(int argc, _TCHAR* argv[])
{
__int8 a=127;
__int8 b=1;
__int16 c=b+a;
__int8 d=b+a;
printf("c=%d,d=%d\n",c,d);
return 0;
}
//result is: c=128, d=-128
I don't understand why c==128! My understanding is that in both additions, b+a are still considered addition of 2 signed 8 bit variables. So the result is an overflow i.e. -128. After that, the result is then promoted to 16 bit signed int for the first assignment operation and c should still get a 16 bit -128 value. Is my understanding correct? The c++ standard is a bit difficult to read. Chapter 4 seems talking about integeral promotion but I can't find anything related to this specific example.
Solution
My understanding is that in both additions, b+a are still considered addition of 2 signed 8 bit variables. So the result is an overflow i.e. -128.
No, the promotion happens before the +
is evaluated, not after it. The addition happens when both a
and b
are positive. Both numbers are promoted to int
s for an addition, added as two positive numbers, and then converted to a 16-bit short. At no point in the process does the result become negative due to an overflow, hence the end result of 128.
Arguably, this makes sense: the behavior of a
and b
matches that of two numbers in mathematics, making it more intuitive to language practitioners.
OTHER TIPS
It's integral promotion.
1 A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int. [§ 4.5]
In this statement
__int16 c=b+a;
First, all
char
andshort int
values are automatically elevated toint
. This process is called integral promotion. Next, all operands are converted up to the type of the largest operand, which is called type promotion. [Herbert Schildt]
The values of variables b
and a
will be promoted to int
and then the operation applies on them.
In twos-complement integer representation, a signed value is represented by setting the highest bit. This allows the machine to add and subtract binary integers with the same instructions, regardless of whether the integer is signed.
a = 127 == 0x7F == 0b01111111
+ b = 1 == 0x01 == 0b00000001
-------------------------------
c = 128 == 0x80 == 0b10000000
d =-128 == 0x80 == 0b10000000
The variables c
and d
may have different types, but different types of integers are merely different interpretations of a single binary value. As you can see above, the binary value fits in 8 bits just fine. Since the standard requires terms of a mathematical expression to be zero- or sign-extended (promoted) to the size of a machine word before any math is done and neither operand will be sign-extended, the result is always 0b10000000
no matter what type the operands are.
In summary, the difference between the results is that, to a 16 bit integer the sign bit is 0b1000000000000000
(which a+b
doesn't have), and to an 8 bit integer the sign bit is 0b10000000
(which a+b
does have).