在 ARM 上混合使用 uint64_t 和 long 会产生奇怪的结果

Mixing uint64_t and long on ARM produces strange results

对 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

在这行代码中:

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 hense 你没有看到这个问题。