【问题标题】:Issue with Integer Conversion整数转换问题
【发布时间】:2012-11-23 10:16:47
【问题描述】:
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 规则,这也应该产生正确的输出。任何想法为什么结果不正确?

【问题讨论】:

    标签: c++ integer type-conversion uac


    【解决方案1】:

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

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

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

    【讨论】:

    • #Steve Jessop,这不应该导致溢出吗?就像 max_int 一样?是否有解释这种行为的规则?
    • @smallB:有符号溢出是 C++ 中未定义的行为,它保证会环绕。它通常确实会回绕(这与您看到的结果一致),但是像 gcc 这样的常见编译器包含的优化可能会破坏您的代码,如果它包含您认为会回绕的溢出,但编译器假设不会发生,因为它们是禁止。 5/4,“如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。”
    【解决方案2】:

    两个操作数都是int,所以算术是在int类型内进行的;运算结果超出int的范围,所以结果未定义。

    为了得到你期望的结果,首先将一个操作数转换为long long

     unsigned long long result = left * (long long) right;
    

    这仍然是潜在的未定义行为;尽早转换为无符号算术更安全(因为无符号算术会换行并且不会溢出):

    unsigned long long result = left * (unsigned long long) right;
    

    注意你得到的结果是0xffffffff80000000;这表明操作的实际结果是int类型中的std::numeric_limits&lt;int&gt;::min(),然后对其进行符号扩展并强制转换为unsigned long long

    【讨论】:

    • @smallB:你期待什么?试试上面的,看看这是不是你想要的。我认为史蒂夫杰索普的上述回答更正确。
    【解决方案3】:

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

    两个参数都是int,所以乘法得到int agein,你是对的,它得到int_max + 1,它等价于int_min=-2147483648。所以它实际上是 -2147483648,但是对于 unsigned long long 它相当于 18446744071562067968,见十六进制代码:

                           int_min =         80000000 
    (unsigned long long) (int min) = ffffffff80000000
    

    【讨论】:

      猜你喜欢
      • 2020-12-02
      • 2021-04-09
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多