讨论this回答我发现以下代码在visual studio中打印-1
和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;
答案 0 :(得分:4)
c1
可能有-128
之类的值。在乘法中,整数提升将导致c1
和c2
在执行操作之前转换为类型int
。
c1 * c2
将成为值int
的{{1}},因此128
将是c1 * c2 / c1
,其值为int
。
-1
对我来说是正确的。
对于第二个版本,通常-1
的结果分配不适合c1 * c2
并且会转换为实现定义的结果,可能是signed char
而不是-128
{1}}。
答案 1 :(得分:2)
整数溢出被认为是UB。这意味着编译器会将(c1 * c2 / c1)
视为完全等同于c2
。
您可以查看this以获取更多信息。
答案 2 :(得分:0)
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,这是排序的第二个结果。
答案 3 :(得分: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。因此结果不同。