我为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
如何获得正确的字符串?
答案 0 :(得分:8)
这看起来像是一种endianess问题,但不是普通的big-endian和little-endian问题。 ARM有时会为double
使用不常见的字节顺序。来自Jean-Michel Muller等人的“浮点运算手册”:
...最接近的双精度数
-7.0868766365730135 x 10^-268
由字节序列编码 记忆中11 22 33 44 55 66 77 88
(从最低到最高 一)在x86和Linux / IA-64平台上(据说它们是 little-endian )和88 77 66 55 44 33 22 11
在大多数PowerPC平台上(据说它们都是 big-endian )。一些架构,例如 因为IA-64,ARM和PowerPC被认为是双端。也就是说,他们可能 根据他们的不同,可以是小端或大端 配置。存在一个例外:一些基于ARM的平台。 ARM处理器 传统上使用浮点加速器(FPA) 体系结构,其中双精度数被分解为 两个32位字的big-endian顺序并按照存储的方式存储 机器的端部,即一般的小端,这意味着 上述数字由序列
55 66 77 88 11 22 33 44
编码。 ARM最近推出了一种新的浮点架构 arithmetic:向量浮点(VFP),其中存储了单词 处理器的本机字节顺序。
以big-endian字节顺序查看时,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调用qlocale.cpp中的QLocalePrivate::doubleToString()
函数将double
转换为字母数字形式。
如果Qt是在定义QT_QLOCALE_USES_FCVT
的情况下编译的,那么QLocalePrivate::doubleToString()
将使用平台的fcvt()
函数来执行转换。如果<{1}} 未定义,则QT_QLOCALE_USES_FCVT
最终会调用QLocalePrivate::doubleToString()
来执行转换。该函数直接检查_qdtoa()
的各个字段,并假设double
采用严格的big-endian或little-endian形式(例如,使用double
和{ {1}}函数分别获取getWord0()
的低位和高位字。
有关详细信息,请参阅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或您自己的文件副本。
假设您的平台正在使用getWord1()
的传统ARM FPA表示(double
的32位一半以big-endian顺序存储,无论整个系统是否为小 - endian),我认为你需要用double
定义来构建Qt。我相信你需要做的就是在构建Qt时将double
选项传递给configure脚本。
答案 1 :(得分:4)
相同的代码使用Qt 4.7.0在x86计算机(运行Windows XP)上生成正确的输出。
我看到了问题根源的以下可能性:
我发现了this forum post类似的问题,假设它可能是一个大/小端转换问题。
我不知道如何解决这个问题,因为我根本没有使用过ARM,但这些信息可能对你有所帮助。