c - 在 Win32 上双重转换为 unsigned int 被截断为 2,147,483,648
问题描述
编译以下代码:
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 文档double
中,没有提到从到的转换中的有符号整数最大值unsigned int
。
当它是函数的返回时,上面的所有值INT_MAX
都被截断。2147483648
我正在使用Visual Studio 2019来构建程序。这不会发生在gcc上。
我做错了吗?有没有安全的转换double
方式unsigned int
?
解决方案
一个编译器错误...
从@anastaciu 提供的程序集中,直接转换代码调用__ftol2_sse
,这似乎将数字转换为有符号的 long。例程名称是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
中并调用双精度到无符号整数转换例程...
直接强制转换的行为不符合 C89;它也不符合任何以后的修订版——甚至C89 也明确表示:
当浮点类型的值转换为无符号类型时,不需要进行整数类型的值转换为无符号类型时进行的余数运算。因此可移植值的范围是[0, Utype_MAX + 1)。
我相信这个问题可能是2005 年的延续- 曾经有一个调用的转换函数__ftol2
可能适用于此代码,即它将值转换为有符号数-2147483647,这将产生正确的解释无符号数时的结果。
不幸__ftol2_sse
的是,它不是 的直接替代品__ftol2
,因为它会 - 而不是按原样采用最低有效值位 - 通过返回LONG_MIN
/来表示超出范围的错误0x80000000
,这里解释为 unsigned long 不是所有的预期。的行为对__ftol2_sse
是有效的signed long
,因为将双精度值 > 转换LONG_MAX
为signed long
将具有未定义的行为。
推荐阅读
- javascript - 如何使用 Angular 8 在重新连接互联网时重新发送失败的 API 请求?
- postgresql - 在 BigQuery 中计算不同的 concat
- mysql - Mysql 查询优化 - 共享查询需要优化
- java - Finding Object in Array of Arrays based in Sub-Object condition
- testing - 有没有办法将所有测试用例从一个 JIRA 项目复制/移动到另一个,我安装了 Xray 插件
- google-cloud-platform - 如何为混合的 HTTPS 和 gRPC 流量设置 GCP LoadBalancer
- ios - AudioKit - 如何使用 AKAmplitudeTracker 阈值回调?
- ios - UITableView insertRows(at: indexPath) 返回无效行数错误
- c++ - 将 AoS 转换为 SoA 时处理组合爆炸
- postgresql - 将 Apache 超集与 PostgreSQL 连接起来