int left = std::numeric_limits<int>::min();
int right = -1;
//the code below instead of give one more than int_max gives: 18446744071562067968
unsigned long long result = left * right;
我试图查找UAC但是根据UAC规则,这应该产生正确的输出。任何想法结果不正确的想法?
答案 0 :(得分:4)
两个操作数均为int
,因此算术在int
类型内执行;操作的结果溢出了int
的范围,因此结果是未定义的。
要获得预期的结果,首先将一个操作数强制转换为long long
:
unsigned long long result = left * (long long) right;
这仍然是潜在的未定义行为;尽可能早地转换为无符号算术更安全(因为无符号算术包装并且不会溢出):
unsigned long long result = left * (unsigned long long) right;
请注意,您得到的结果是0xffffffff80000000
;这表示该操作的实际结果为std::numeric_limits<int>::min()
类型int
,然后进行符号扩展并转换为unsigned long long
。
答案 1 :(得分:4)
将有符号2的补码int
的最小值乘以-1是未定义的行为,因为结果超出了类型的范围。
在这种情况下,您的输出与-2147483648的结果一致,即溢出似乎已经缠绕。您不能依赖签名类型的环绕,只能使用无符号类型。
将计算结果分配给unsigned long long
并不会改变执行计算的类型。一旦进行乘法,就会丢失。因此,在乘法之前将其中一个操作数转换为unsigned long long
。
答案 2 :(得分:0)
原因是乘法是按int
提交的。
这两个参数都是int
,因此乘法会产生int
年龄,而你是对的,它给出了int_max
+ 1,相当于int_min
= - 2147483648。所以它实际上是-2147483648,但是对于无符号长整数,它相当于18446744071562067968,参见十六进制代码:
int_min = 80000000
(unsigned long long) (int min) = ffffffff80000000