讨论this回答我发现下面的代码在visual studio中打印-1
和1
。为什么?在我看来,它应该在乘法运算期间打印出两个零碎的溢出。带符号字符乘法的问题
signed char c1 = numeric_limits<signed char>::min();
signed char c2 = -1;
cout << c1 * c2/c1 << endl;
signed char result = c1 * c2;
cout << result/c1 << endl;
讨论this回答我发现下面的代码在visual studio中打印-1
和1
。为什么?在我看来,它应该在乘法运算期间打印出两个零碎的溢出。带符号字符乘法的问题
signed char c1 = numeric_limits<signed char>::min();
signed char c2 = -1;
cout << c1 * c2/c1 << endl;
signed char result = c1 * c2;
cout << result/c1 << endl;
c1
可能有这样-128
的值,说。在乘法中,在执行操作之前,整数升级将导致c1
和c2
转换为类型int
。然后
c1 * c2
将是一个与int
值128
所以c1 * c2/c1
将是一个与int
值-1
。
-1
第一个输出看起来正确的给我。
对于第二个版本,通常的c1 * c2
结果的分配将不适合一个signed char
和将被转化为实现定义的结果,也许是-128
代替128
。
整数溢出被认为是UB。这意味着编译器将认为(c1 * c2/c1)
完全等同于c2
。
您可以检查this了解更多信息。
'c1 * c2'可能不会涉及任何_signed_整数溢出,除非平台具有相同大小的'char'和'int'。 – 2011-04-30 10:11:36
@Charles:它没有(它是Visual Studio)。 – 2011-04-30 10:17:32
c1 * c2
为int
乘法(5/9标准)。我们知道MSVC上的CHAR_BIT是8,并且它使用两个补码表示来表示签名类型,所以我们知道这个值:-128 * -1是128.
128/-128是-1,所以这是第一个结果排序。
分配-CHAR_MIN
到signed char
具有实现定义的结果(4.7/3),但我们知道在MSVC结果为-128。然后-128/-1是1,所以这是排序的第二个结果。
第一种情况,使得升频为int明确:
cout << ((int)c1 * c2/c1 << endl;
第二种情况下,分配到一个中间变量相当于
cout << ((signed char)((int)c1 * c2))/c1 << endl;
(隐式转换为INT由编译器完成作出了明确。)
二进制补码,由-1型的最大负值乘以离开价值不变,如果它被限制在相同数量的位。所以,第二个例子,c1 * c2 == c1。尽管乘法是以int形式完成的,但它会转换回char的宽度。
在第一个例子中,整个calaulation完成作为int,所以操作具有多个位的工作,并且因此不会被截掉。这里,c1 * c2 ==(c1 * -1)== -c1。因此,不同的结果。
对int的提升是多余的,无论如何这个实现都是这样做的。在这种情况下,在'(signed char)((int)c1 * c2)'算术运算没有溢出,有一个从一个整数类型到另一个整数类型的显式转换。这将是实现定义的,而不是未定义的行为。 – 2011-04-30 10:29:00
但是为什么'c1 * c2'会变成'int'?这是标准吗? – 2011-04-30 10:12:30
@Mhhhran因为整数推广 – 2011-04-30 10:14:16
@MhhranHovespyan:积分促销适用于'*'的两个操作数,所以'signed char'在执行乘法操作之前都会被提升为'int'。 – 2011-04-30 10:14:46