x86_64与aarch64架构下double转int溢出行为差异原因及统一方法
浮点转整数的跨架构行为差异与解决方案
问题现象
以下代码在x86_64和aarch64平台编译执行后输出不同:
#include <iostream> int main() { double d = 2147483649; int i = d; std::cout << i << std::endl; return 0; }
- x86_64平台输出:
-2147483648 - aarch64平台输出:
2147483647
编译命令均为:g++ a.cpp -o a
差异原因
核心原因是C++标准将「浮点值超出目标整数类型范围的转换行为」定义为未定义行为,编译器可根据目标架构的硬件特性自由实现转换逻辑:
- x86_64平台的GCC默认使用x86指令集的
cvttsd2si指令,该指令对超出32位int范围的浮点值直接做二进制截断:2147483649的二进制表示为10000000000000000000000000000001,截断为32位有符号int后,最高位为1(表示负数),按补码规则结果为-2147483648。 - aarch64平台的GCC默认使用ARM64指令集的
fcvtzs指令,该指令会将超出范围的浮点值饱和到整数类型的最值:2147483649超过32位int的最大值2147483647,因此直接返回该最大值。
统一行为的方法
要让aarch64平台的输出与x86_64一致,可通过GCC编译选项强制使用截断式转换:
使用以下命令编译:
g++ -ffp-int-builtin-inexact a.cpp -o a
该选项会禁用aarch64默认的饱和转换逻辑,转而采用与x86_64一致的二进制截断行为,此时程序输出将变为-2147483648。
另外,也可使用等价选项:
g++ -mno-fp-int-builtin-saturate a.cpp -o a
内容的提问来源于stack exchange,提问作者Ajith Gupta
相关产品推荐
相关产品推荐

