将uint32_t强制转换为uint64_t会导致不同的值吗?

14

我使用Visual Studio 2015 C++版本14.0.25431.01 Update 3,我的代码出现了意外行为。在64位Release模式下编译和运行:

#include <iostream>
#include <stdint.h>

int main(int, char**) {
    for (uint32_t i = 1; i < 3; ++i) {
        uint32_t a = i * 0xfbd1e995;
        uint64_t b = a;

        std::cout << a << " 32bit" << std::endl;
        std::cout << b << " 64bit" << std::endl;
    }
}

我期望ab具有相同的值,但是当我运行代码时,输出结果如下:

4224838037 32bit
4224838037 64bit
4154708778 32bit
8449676074 64bit

看起来编译器用64位乘法代替了32位乘法。这样做是允许的吗,还是这是编译器的错误?g++和clang都给我预期的结果。

编辑:我已经用一个更简单的版本更新了我的代码,但是仍有同样的问题。此外,我刚刚提交了一份错误报告


1
相同奇怪的结果,使用Studio 2010 x64版本发布。 - Christian Ammer
1
“这样做是允许的吗,还是这是编译器的错误?”那将是一个非常严重的编译器错误。你确定你运行的代码真的是这个吗? - Baum mit Augen
1
我也可以重现这个问题,当使用VS2013并在发布模式下编译时。 - Algirdas Preidžius
使用 /O2 或 /Ox 编译会导致奇怪的行为,而 /Od 或 /O1 则会产生预期的输出。 - Christian Ammer
我刚刚提交了一个错误报告。 - martinus
显示剩余5条评论
2个回答

7

我能在VS2010上重现这个问题,而直接的原因是这样的:

add ebx, 5BD1E995h  ; this is x
add rdi, 5BD1E995h  ; this is a 64bit version of x

由于这是一个64位加法,因此它将仅进入高32位。这至少比想出一个64位乘法更有意义,在归纳变量消除中可能是一个特例,但这只是猜测。

还有趣的是,即使编译错误也不会通过保存强制转换来解决。正确的值就在rbx中。


1
为什么用add表示乘法?不管怎样,似乎在CL19中已经找不到了。我只能找到具有1540483477值的imul - phuclv
2
我认为编译器试图变得聪明,用常数替换循环计数器乘以常数的0到50的循环,只需添加常数。 - martinus


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接