2011-04-30 85 views
0

讨论this回答我发现下面的代码在visual studio中打印-11。为什么?在我看来,它应该在乘法运算期间打印出两个零碎的溢出。带符号字符乘法的问题

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; 

回答

4

c1可能有这样-128的值,说。在乘法中,在执行操作之前,整数升级将导致c1c2转换为类型int。然后

c1 * c2将是一个与int128所以c1 * c2/c1将是一个与int-1

-1第一个输出看起来正确的给我。

对于第二个版本,通常的c1 * c2结果的分配将不适合一个signed char和将被转化为实现定义的结果,也许是-128代替128

+0

但是为什么'c1 * c2'会变成'int'?这是标准吗? – 2011-04-30 10:12:30

+0

@Mhhhran因为整数推广 – 2011-04-30 10:14:16

+0

@MhhranHovespyan:积分促销适用于'*'的两个操作数,所以'signed char'在执行乘法操作之前都会被提升为'int'。 – 2011-04-30 10:14:46

2

整数溢出被认为是UB。这意味着编译器将认为(c1 * c2/c1)完全等同于c2

您可以检查this了解更多信息。

+2

'c1 * c2'可能不会涉及任何_signed_整数溢出,除非平台具有相同大小的'char'和'int'。 – 2011-04-30 10:11:36

+0

@Charles:它没有(它是Visual Studio)。 – 2011-04-30 10:17:32

0

c1 * c2int乘法(5/9标准)。我们知道MSVC上的CHAR_BIT是8,并且它使用两个补码表示来表示签名类型,所以我们知道这个值:-128 * -1是128.

128/-128是-1,所以这是第一个结果排序。

分配-CHAR_MINsigned char具有实现定义的结果(4.7/3),但我们知道在MSVC结果为-128。然后-128/-1是1,所以这是排序的第二个结果。

0

第一种情况,使得升频为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。因此,不同的结果。

+0

对int的提升是多余的,无论如何这个实现都是这样做的。在这种情况下,在'(signed char)((int)c1 * c2)'算术运算没有溢出,有一个从一个整数类型到另一个整数类型的显式转换。这将是实现定义的,而不是未定义的行为。 – 2011-04-30 10:29:00