[英]Wrong conversion from double to QString in Qt on ARM
我有为ARMv5TE构建的Qt 4.4.3。 我尝试将double
转换为QString
:
#include <QtCore/QtCore>
#include <cmath>
int main(int argc, char** argv)
{
const double pi = M_PI;
qDebug() << "Pi is : " << pi << "\n but pi is : " << QString::number(pi, 'f', 6);
printf("printf: %f\n",pi);
return 0;
}
但得到奇怪的输出:
Pi is : 8.6192e+97
but pi is : "86191995128153827662389718947289094511677209256133209964237318700300913082475855805240843511529472.0000000000000000"
printf: 3.141593
我如何获得正确的字符串?
这看起来像是一种endianess问题,但不是普通的big-endian和little-endian问题。 ARM有时会使用异常的字节顺序进行double
。 来自Jean-Michel Muller等人的“浮点运算手册”:
...最接近
-7.0868766365730135 x 10^-268
的双精度数字由x86和Linux /上的内存字节序列11 22 33 44 55 66 77 88
编码(从最低到最高) IA-64平台(据说它们是小端 )和88 77 66 55 44 33 22 11
在大多数PowerPC平台上(据说它们都是大端 )。 一些架构,例如IA-64,ARM和PowerPC,据说是双端的 。 即,根据其配置,它们可能是小端或大端。存在一个例外:一些基于ARM的平台。 ARM处理器传统上使用浮点加速器 (FPA)架构,其中双精度数字按大端顺序分解为两个32位字,并根据机器的字节顺序存储,即little-endian通常,这意味着上述数字由序列
55 66 77 88 11 22 33 44
编码。 ARM最近推出了一种新的浮点运算架构: 向量浮点 (VFP),其中的单词以处理器的本机字节顺序存储。
当以big-endian字节顺序M_PI
时, M_PI
将具有如下表示:
0x400921fb54442d18
接近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()
中的QLocalePrivate::doubleToString()
函数将double
转换为字母数字形式。
如果Qt是在定义了QT_QLOCALE_USES_FCVT
情况下编译的,那么QLocalePrivate::doubleToString()
将使用平台的fcvt()
函数来执行转换。 如果QT_QLOCALE_USES_FCVT
没有定义,则QLocalePrivate::doubleToString()
结束调用_qdtoa()
来执行转换。 该函数直接检查double
的各个字段,并假设double
是严格的big-endian或little-endian形式(例如,使用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
(无论整个系统是否为little-endian, double
端的32位半部都以big-endian顺序存储),我认为你需要构建Qt定义了QT_QLOCALE_USES_FCVT
。 我相信你需要做的就是在构建Qt时将-DQT_QLOCALE_USES_FCVT
选项传递给configure脚本。
相同的代码在Qt 4.7.0的x86机器(运行Windows XP)上产生适当的输出。
我看到了问题根源的以下可能性:
我发现这个论坛帖子上有一个类似的问题,假设它可能是一个大/小端转换问题。
我无法告诉如何解决这个问题,因为我根本没有使用过ARM,但这些信息可能对你有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.