这看起来是一种字节序问题,但不是您的普通大端与小端问题。ARM 有时对double
. 来自 Jean-Michel Muller 等人的“浮点算术手册”:
...最接近的双精度数
在 x86 和 Linux/IA-64 平台上由内存-7.0868766365730135 x 10^-268
中的字节序列(从最低到最高)编码
11 22 33 44 55 66 77 88
(据说它们是
little-endian)和在88 77 66 55 44 33 22 11
大多数 PowerPC 平台上(据说它们是big-endian)。一些架构,例如 IA-64、ARM 和 PowerPC,据说是双端的。即,它们可能是小端或大端,具体取决于它们的配置。
存在一个例外:一些基于 ARM 的平台。ARM处理器传统上采用浮点加速器(FPA)架构,双精度数按big-endian顺序分解为两个32位字,并根据机器的字节序,即little-endian存储一般来说,这意味着上面的数字是由序列编码的55 66 77 88 11 22 33
44
。ARM 最近推出了一种用于浮点运算的新架构:向量浮点(VFP),其中字以处理器的本机字节顺序存储。
当以大端字节顺序查看时,M_PI
将具有如下所示的表示:
0x400921fb54442d18
由 wil 近似的大数8.6192e+97
具有如下表示:
0x54442d18400921fb
如果仔细观察,这两个 32 位字是交换的,但 32 位字内的字节顺序是相同的。显然,ARM“传统”双点格式似乎混淆了 Qt 库(或 Qt 库配置错误)。
我不确定处理器是否使用传统格式并且 Qt 期望它采用 VFP 格式,或者情况是否相反。但这似乎是这两种情况之一。
我也不确定如何解决这个问题——我猜有一些选项可以构建 Qt 来正确处理这个问题。
以下代码片段至少会告诉您double
编译器正在使用什么格式,这可以帮助您缩小 Qt 中需要更改的范围:
unsigned char* b;
unsigned char* e;
double x = -7.0868766365730135e-268;
b = (unsigned char*) &x;
e = b + sizeof(x);
for (; b != e; ++b) {
printf( "%02x ", *b);
}
puts("");
一个普通的小端机器将显示:
11 22 33 44 55 66 77 88
更新一点分析:
目前,我无法对此进行任何真正的调试(目前我什至无法访问我的工作站),但是通过查看http://qt.gitorious.org上提供的 Qt 源代码,这里是补充分析:
看起来 Qt 调用了QLocalePrivate::doubleToString()
qlocale.cpp 中的函数以将 a 转换double
为字母数字形式。
如果 Qt 是用QT_QLOCALE_USES_FCVT
定义的方式编译的,那么QLocalePrivate::doubleToString()
将使用平台的fcvt()
函数来执行转换。如果未定义,则QT_QLOCALE_USES_FCVT
最终调用以执行转换。该函数直接检查 the 的各个字段,并且似乎假定 the是严格的大端或小端形式(例如,使用and函数分别获取 the 的低位和高位字)。QLocalePrivate::doubleToString()
_qdtoa()
double
double
getWord0()
getWord1()
double
请参阅http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale.cpp和http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib /tools/qlocale_tools.cpp或您自己的文件副本以获取详细信息。
假设您的平台使用传统的 ARM FPA 表示double
(其中 32 位的一半以double
大端顺序存储,无论整个系统是否为小端),我认为您需要构建 QtQT_QLOCALE_USES_FCVT
定义的。我相信您需要做的就是-DQT_QLOCALE_USES_FCVT
在构建 Qt 时将选项传递给配置脚本。