ARM上Qt中从double到QString的错误转换

Ren*_*pov 8 c++ qt arm

我有为ARMv5TE构建的Qt 4.4.3.我尝试将a转换doubleQString:

#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;
}  
Run Code Online (Sandbox Code Playgroud)

但得到奇怪的输出:

Pi is :  8.6192e+97 
but pi is :  "86191995128153827662389718947289094511677209256133209964237318700300913082475855805240843511529472.0000000000000000"
printf: 3.141593
Run Code Online (Sandbox Code Playgroud)

我如何获得正确的字符串?

Mic*_*urr 8

这看起来像是一种endianess问题,但不是普通的big-endian和little-endian问题.ARM有时会使用不常见的字节顺序double.来自Jean-Michel Muller等人的"浮点运算手册":

...最接近的双精度数 -7.0868766365730135 x 10^-26811 22 33 44 55 66 77 88x86和Linux/IA-64平台上的内存中的字节序列(从最低到最高)编码 (它们被认为是 小端)和通过88 77 66 55 44 33 22 11在大多数的PowerPC平台(他们说是大端).一些架构,例如IA-64,ARM和PowerPC,据说是双端的.也就是说,根据它们的配置,它们可能是小端或大端.

存在一个例外:一些基于ARM的平台.ARM处理器传统上使用的浮点加速器(FPA)结构中,其中的双精度数在大端顺序根据机器,即,小端的字节序分解为两个32位字并存储通常,这意味着上述数字由序列编码55 66 77 88 11 22 33 44.ARM公司最近推出了一种新的架构用于浮点算术运算:向量浮点(VFP),其中,所述字被存储在处理器的本机字节顺序.

当以big-endian字节顺序查看时,M_PI将具有如下所示的表示:

0x400921fb54442d18
Run Code Online (Sandbox Code Playgroud)

8.6192e+97wil 近似的大数字表示如下:

0x54442d18400921fb
Run Code Online (Sandbox Code Playgroud)

如果仔细观察,会交换两个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("");
Run Code Online (Sandbox Code Playgroud)

一个普通的小端机器将显示:

11 22 33 44 55 66 77 88
Run Code Online (Sandbox Code Playgroud)

通过更多分析更新:

目前,我无法对此进行任何实际调试(我现在甚至无法访问我的工作站),但是通过查看http://qt.gitorious.org上提供的Qt源代码,这里是附加分析:

看起来Qt调用QLocalePrivate::doubleToString()qlocale.cpp中的函数将a转换double为字母数字形式.

如果Qt是使用QT_QLOCALE_USES_FCVTdefined 编译的,那么QLocalePrivate::doubleToString()将使用平台的fcvt()函数来执行转换.如果QT_QLOCALE_USES_FCVT没有定义,则QLocalePrivate::doubleToString()结束调用_qdtoa()来执行转换.该函数double直接检查各个字段,并假设它double处于严格的大端或小端形式(例如,使用getWord0()getWord1()函数分别得到低位和高位字double).

请参阅http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale.cpphttp://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib /tools/qlocale_tools.cpp或您自己的文件副本以获取详细信息.

假设您的平台正在使用传统的ARM FPA表示double(double无论整个系统是否为little-endian,32位的一半以big-endian顺序存储),我认为你需要构建Qt与该QT_QLOCALE_USES_FCVT定义.我相信你需要做的就是-DQT_QLOCALE_USES_FCVT在构建Qt时将选项传递给configure脚本.