【问题标题】:Mixing uint64_t and long on ARM produces strange results在 ARM 上混合 uint64_t 和 long 会产生奇怪的结果
【发布时间】:2019-08-22 13:48:50
【问题描述】:

在 uint64_t 和 long 的混合上使用算术会在 arm(c++ 编译器)上产生不需要的结果。相同的代码在 x86 上按预期工作。

如果 long 替换为 uint64_t,它会按预期工作。

Armv7 编译器为 c++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516

这里也有代码:http://cpp.sh/2xrnu

int main()
{
    uint64_t x = 1000UL * 60 * 60 * 24 * 31;
    int i1 = 31;
    long l2 = 1000 * 60 * 60 * 24;
    uint64_t u2 = 1000 * 60 * 60 * 24;
    std::cout << "x        : " << x << std::endl;
    std::cout << "i1       : " << i1 << std::endl;
    std::cout << "l2       : " << l2 << std::endl;
    std::cout << "u2       : " << u2 << std::endl;
    std::cout << "x - i1*l2: " << x - i1 * l2 << std::endl; // expected '0', got 4294967296
    std::cout << "x - i1*u2: " << x - i1 * u2 << std::endl; // expected and got '0'
    return 0;
}

我希望最后两行给出 '0'。

在 x86 上,结果是

i1       : 31
l2       : 86400000
u2       : 86400000
x - i1*l2: 0
x - i1*u2: 0

在 Arm (CortexA8) 上,结果是

i1       : 31
l2       : 86400000
u2       : 86400000
x - i1*l2: 4294967296
x - i1*u2: 0

【问题讨论】:

  • 这个表达式 1000 * 60 * 60 * 24;具有 int 类型。这个表达式 1000UL * 60 * 60 * 24 * 31;具有 unsigned long 类型。
  • 那个平台上的sizeof(int)sizeof(long)是什么?
  • @vlad-from-moscow 即使我将 1000 * 60 * 60 * 24 更改为 1000L * 60 * 60 * 24,问题仍然存在。而 1000 * 60 * 60 * 24 是 86400000,远低于 int max 吗?
  • 31 * 86400000 不适合 31 位...您正在从整数溢出中查看 UB。
  • 最好static_cast&lt;uint64_t&gt;() 更安全,更易读。

标签: c++ arm armv7 uint64


【解决方案1】:

在这行代码中:

std::cout << "x - i1*l2: " << x - i1 * l2 << std::endl; // expected '0', got 4294967296

当您将 31 乘以 86400000 时,您会得到 2678400000,即 0x9FA52400,它不适合 4 字节的有符号长整数(符号位设置为 1)。然后你得到 UB 由于有符号溢出和垃圾值转换为uint64_t 以从 x 中减去它。在 x86 上,您显然有更大的long,因此您看不到问题。

【讨论】:

  • 是的,就是这样。我完全监督了这个中间结果。感谢 Slava 和@MaxLanghof
猜你喜欢
  • 2011-05-08
  • 2015-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多