编译以下代码:

double getDouble()
{
    double value = 2147483649.0;
    return value;
}

int main()
{
     printf("INT_MAX: %u\n", INT_MAX);
     printf("UINT_MAX: %u\n", UINT_MAX);

     printf("Double value: %f\n", getDouble());
     printf("Direct cast value: %u\n", (unsigned int) getDouble());
     double d = getDouble();
     printf("Indirect cast value: %u\n", (unsigned int) d);

     return 0;
}

输出(MSVC X86):

INT_MAX: 2147483647
UINT_MAX: 4294967295
Double value: 2147483649.000000
Direct cast value: 2147483648
Indirect cast value: 2147483649

输出(MSVC X64):

INT_MAX: 2147483647
UINT_MAX: 4294967295
Double value: 2147483649.000000
Direct cast value: 2147483649
Indirect cast value: 2147483649

Microsoft documentation中,从doubleunsigned int的转换中没有提到有符号整数的最大值.

当返回函数时,所有大于INT_MAX的值都将被截断为2147483648.

我用Visual Studio 2019来建立这个程序.这不会发生在gcc.

我做错什么了吗?有没有安全的方法将double转化为unsigned int

推荐答案

一个编译器错误...

从@anastaciu提供的程序集中,直播代码调用__ftol2_sse,这似乎将数字转换为signed long. routine 名为ftol2_sse,因为这是一台支持sse的机器,但浮点值位于x87浮点寄存器中.

; Line 17
    call    _getDouble
    call    __ftol2_sse
    push    eax
    push    OFFSET ??_C@_0BH@GDLBDFEH@Direct?5cast?5value?3?5?$CFu?6@
    call    _printf
    add esp, 8

另一方面,间接演员扮演的角色则是这样

; Line 18
    call    _getDouble
    fstp    QWORD PTR _d$[ebp]
; Line 19
    movsd   xmm0, QWORD PTR _d$[ebp]
    call    __dtoui3
    push    eax
    push    OFFSET ??_C@_0BJ@HCKMOBHF@Indirect?5cast?5value?3?5?$CFu?6@
    call    _printf
    add esp, 8

它弹出双精度值并将其存储到局部变量,然后将其加载到SSE寄存器并调用__dtoui3,这是一个双精度到无符号整数转换 routine ...

直接强制转换的行为不符合C89;它也不符合任何后续修订-even C89明确规定:

整数类型的值转换为无符号类型时执行的余数运算,不需要在浮点类型的值转换为无符号类型时执行.因此,可移植值的范围为[0, Utype_MAX + 1).


我相信问题可能是continuation of this from 2005——以前有一个名为__ftol2的转换函数,它可能会对这段代码起作用,也就是说,它会将值转换为signed number-2147483647,当解释一个无符号数字时,会产生正确的结果.

不幸的是,__ftol2_sse并不是__ftol2的替代品,因为它将通过返回LONG_MIN/0x80000000(这里被解释为无符号长)来发出超出范围的错误信号,而不只是按原样取最低有效值位.__ftol2_sse的行为对signed long有效,因为双a值的转换>;LONG_MAXsigned long会有未定义的行为.

C++相关问答推荐

位屏蔽对于无符号转换是强制的吗?

intellisense不工作,甚至已经下载了c/c++扩展

C指针地址和转换

在#include中使用C宏变量

为什么GCC在每次循环迭代时都会生成一个数组的mov&S使用[]访问数组?(-03,x86)

X86/x64上的SIGSEGV,由于原始内存访问和C中的DS寄存器之间的冲突,在Linux上用TCC编译为JIT引擎

为什么该函数不将参数值保存到数据 struct 中?

在CLANG中调试预处理器宏

GCC不顾-fno-Builtin-SINCOS旗帜向SINCOS发出呼唤

什么是.c.h文件?

为什么我从CSV文件中进行排序和搜索的代码没有显示数据的所有结果?

在C++中父进程和子进程中的TAILQ队列同步问题

类型定义 struct 与简单的类型定义 struct

错误...的多个定义(&Q)首先在这里定义&

C代码可以在在线编译器上运行,但不能在Leetcode上运行

哪个首选包含第三个库S头文件?#INCLUDE;文件名或#INCLUDE<;文件名&>?

如何解释数组中的*(ptr)和*(ptr+2)?

当读取可能会阻塞管道中的父进程时,为什么要等待子进程?

计算时出现奇怪的计算错误;N Select K;在C中

通过GTK';传递回调参数;s g_signal_connect()导致C中出现意外值