0
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 规则,这也应该产生正确的输出。任何想法为什么结果不正确?

4

3 回答 3

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.

于 2012-11-23T10:22:17.787 回答
4

将有符号 2 的补码的最小值乘以int-1 是未定义的行为,因为结果超出了类型的范围。

在这种情况下,您的输出与 -2147483648 的结果一致,即溢出似乎已经环绕。您不能依赖有符号类型的环绕,只能依赖无符号类型。

将计算结果分配给unsigned long long不会改变执行计算的类型。只要你做乘法,你就输了。因此,在乘法unsigned long long 之前将其中一个操作数转换为。

于 2012-11-23T10:23:37.757 回答
0

原因是乘法是根据 提交的int

两个参数都是int,所以乘法给出了一个intagein,你是对的,它给出了int_max+ 1 ,相当于int_min=-2147483648。所以它实际上是 -2147483648,但是对于 unsigned long long 它相当于 18446744071562067968,请参见十六进制代码:

                       int_min =         80000000 
(unsigned long long) (int min) = ffffffff80000000
于 2012-11-23T10:30:58.787 回答