混合整数类型的 C++ 算术导致溢出
-
21-12-2019 - |
题
我在VC++2010中做了一些混合不同大小的操作数导致加法运算溢出的测试:
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
我不明白为什么c==128!我的理解是,在这两种加法中,b+a仍然被认为是2个带符号的加法 8位 变量。所以结果是溢出,即-128。 在那之后, ,然后将结果提升为 16 位有符号 int 以进行第一次赋值操作,并且 c 仍应获得 16 位 -128 值。我的理解正确吗?C++ 标准有点难以阅读。第 4 章似乎在讨论整数提升,但我找不到与这个特定示例相关的任何内容。
解决方案
我的理解是,在这两种加法中,b+a仍然被认为是2个带符号的8位变量的加法。所以结果是溢出,即-128。
不,促销活动发生在 +
是被评估的,而不是在评估之后。当两者都存在时,就会发生加法 a
和 b
是积极的。两个号码都提升为 int
s 进行加法,作为两个正数相加,然后转换为 16 位短整型。在此过程中任何时候结果都不会因溢出而变为负数,因此最终结果为 128。
可以说,这是有道理的:的行为 a
和 b
与数学中的两个数字相匹配,使语言实践者更加直观。
其他提示
就是积分促销。
1 如果 int 可以表示源类型的所有值,则除 bool、char16_t、char32_t 或 wchar_t 之外的整数类型的纯右值(其整数转换等级 (4.13) 小于 int 的等级)可以转换为 int 类型的纯右值;否则,可以将源纯右值转换为 unsigned int 类型的纯右值。[第4.5节]
在这份声明中
__int16 c=b+a;
首先,所有
char
和short int
值自动提升至int
. 。这个过程称为 积分推广. 。接下来,将所有操作数向上转换为最大操作数的类型,这称为 类型推广. 。[赫伯特·希尔特]
这 价值观 变量数 b
和 a
将晋升为 int
然后对它们应用操作。
在二进制补码整数表示中,通过设置最高位来表示有符号值。这允许机器使用相同的指令对二进制整数进行加法和减法,无论整数是否有符号。
a = 127 == 0x7F == 0b01111111
+ b = 1 == 0x01 == 0b00000001
-------------------------------
c = 128 == 0x80 == 0b10000000
d =-128 == 0x80 == 0b10000000
变量 c
和 d
可能有不同的类型,但不同类型的整数只是单个二进制值的不同解释。正如您在上面看到的,二进制值正好适合 8 位。由于该标准要求将数学表达式的项进行零或符号扩展(提升)到机器字的大小 前 完成任何数学运算并且两个操作数都不会进行符号扩展,结果始终是 0b10000000
无论操作数是什么类型。
综上所述,结果之间的差异在于,对于 16 位整数,符号位为 0b1000000000000000
(哪个 a+b
没有),对于 8 位整数,符号位是 0b10000000
(哪个 a+b
确实有)。