将(ASCII)字符字符串转换为浮点数 - C/C++和Matlab

3
我需要帮助将ASCII字符字符串转换为单精度浮点数。我的数据格式如下:
ìÀV3é¾V3»V3AÀV3ÁV3Û¶V3ÅV3=¾V3âºV3ðÂV3߸V3¿V3é¾V3ÁV3Û¶V3é¾V3ìÀV3ÁV3é¾V3ÁV3=¾V3DÂV3DÂV30¶V¿V3:¼V3¿V3ìÀV3,´V3¿V3·V3ìÀV3
每四个字符应表示一个浮点数,例如:50.90101e-9;
我正在尝试使用以下C++代码将此字符串转换为可读数据。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>


int main (void)
{
    int i;
    int no_of_bytes;
    char temp_string[2048];
    float this_reading[100];
    char *ptr;
    no_of_bytes=32;

    sprintf(temp_string,"%i",no_of_bytes*4);

    /*convert char string to floating point*/
    sprintf(temp_string,"%i","ìÀV3é¾V3»V3AÀV3ÁV3Û¶V3ÅV3=¾V3âºV3ðÂV3߸V3¿V3é¾V3ÁV3Û¶V3é¾V3ìÀV3ÁV3é¾V3ÁV3=¾V3DÂV3DÂV30¶V¿V3:¼V3¿V3ìÀV3,´V3¿V3·V3ìÀV3");
    ptr=&temp_string [1];
    /*convert char string to floating point*/
    for(i=0; i<no_of_bytes; i++)
    {
        //puts(ptr);
        this_reading [i] = *((float*)ptr);
        ptr = ptr+4;
        printf ("%e \n", this_reading [i]);
    }
}
/*end of main*/

但我得到了以下结果:
6.665629e-10 
-6.321715e-30 
4.056162e-02 
-5.629500e+14 
1.259217e-18 
1.779649e-43 
3.087247e+23 
2.350968e-38 
-2.437012e+01 
9.439035e-38 
0.000000e+00 
-2.000000e+00 
-nan 
1.661560e+35 
4.056162e-02 
-5.629500e+14 
1.259217e-18 
1.779649e-43 
3.096102e+23 
2.350968e-38 
-2.437012e+01 
1.628646e+32 
0.000000e+00 
6.490371e+32 
0.000000e+00 
0.000000e+00 
2.596148e+33 
0.000000e+00 
1.038459e+34 
4.153837e+34 
0.000000e+00 
0.000000e+00

我尝试获取一个接近要转换的值的浮点数,将其转换为字符再使用相同的方法转换回浮点数,但结果仍然出现了相同的错误:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>

int main (void)
{

    float reading;
    float number;
    char *ptr;
    float *pointer_number;
    char temp_char ;

    number = 50.90101e-9;
   pointer_number = & number;

    printf ("%e \n",*pointer_number);
    temp_char  = *((char*)pointer_number);

    printf ("%c \n",temp_char);

   ptr=&temp_char ;
    puts(ptr);

    reading  = *((float*)ptr);
    printf ("%f \n", reading);

}
/*end of main*/

.

5.090101e-08 
A 
AA�Z3
22272396874481664.000000 

我不是C/C++数据声明和操作方面的专家。我的最终目的是在Matlab中进行此转换。 我正在从一个非常古老的仪器读取此值。他们在仪器手册中指定,查询数据使用IEEE浮点算术标准(ANSI/IEEE Std. 754-1985)支持两种数据类型的大小。

谢谢!


3
第一个字符串大部分看起来不是 ASCII 字符。 - Carl Norum
2
你在问题标签中打了C的标签,但在问题正文中却说了C++,不过你的代码看起来像是C语言,除了#include <iostream>这一行是C++的。请确定你使用的编程语言是哪一个... - R.. GitHub STOP HELPING ICE
你可能认为你的数据看起来是那样的,但我认为在某个地方,你的数据是一个错误地显示为字符串的字节数组。有一些字节值无法打印成ASCII字符,因此这种转换可能会破坏数据。如果你必须要使用ASCII,请使用十六进制转换或其他方法。 - Peter
代码在该仪器手册中显示为C/C++。实际上,这些数据看起来像这样。我正在“窃听”我的GPIB通信通道,这就是我收到的内容。我还有一个非常老的Windows软件(来自于这个仪器),可以进行相同的读取。该软件读取相同的数据,并且可以显示这些值。 - uhnucross
1
您发布的字符看起来不像是常见的IEEE 754格式的浮点数据,无论是float还是double,小端或大端,从初始字节或下一个字节开始,所有解释都会产生非常大或非常小的值。(例如,我找到的最接近1的幅度是-2.22482e-06。)如果在将它们复制到Stack Overflow的过程中更改了这些字符,请确保在实际程序中它们没有被更改。如果您无法在不更改的情况下读取实际的二进制数据,则比转换更大的问题。 - Eric Postpischil
1
@Eric Postpischil 我也遇到了类似的问题。对我来说,Cygwin Eclipse Juno Service Release 2将所谓的ASCII字符串转换为UTF8编码,这使得浮点数叠加成为了问题。我将该字符串放入一个带有“ASCII”(错误)编码的文件中,然后以二进制形式读取,获得更好的成功率。仍然认为OP提供的字符串与OP某处拥有的真实二进制数据不匹配。 - chux - Reinstate Monica
2个回答

2

你的问题在于temp_string中含有垃圾数据。

sprintf(temp_string,"%i", string_literal)

这里存在错误。 %i 不能与字符指针兼容,但由于 sprintf 是一个可变参数函数,编译器不知道您有类型不匹配的问题。

去掉 sprintf,尝试使用以下代码

const char* ptr = "...";

然后您的循环就应该能够工作了。

甚至更简单的方法:

const float *this_reading = (float*)"...";

然后像使用数组一样使用它。

当然,所有这些代码都假设数据的字节顺序与C++平台匹配。但如果您更关心数字计算,那么它应该“足够好地”工作。


1

前10个值为

0 5.000122e-08
1 4.999939e-08
2 ?
3 5.000061e-08
4 ?
5 4.999206e-08
6 4.985647e-08
7 4.999878e-08
8 4.999573e-08
9 5.000305e-08
...

你提供的50.90101e-9转换成我的4字节小端浮点数C计算机上的A � Z 3。由于Z 3类似于每第3、4个字符(几乎相同),这暗示了你的字符串具有相同的小端浮点格式。将你的字符串放入C文件中存在两个问题。在我的C文件中,它将“ìÀV3é¾ ...”字符串转换为UTF8编码。通过联合浮点数导致混淆。按照你呈现的方式,你的字符串肯定缺少一些字节。(我添加了一些来跨越第二个浮点数。)我假设真实的字符串以其原始形式在文件中可用。以二进制方式打开该文件,并每次以4个字节作为float读取该文件。

FILE *inf = fopen("Stringfilename", "rb");
int i = 0;
float f;
while (fread(&f, sizeof(f), 1, inf) == 1) {
  printf("%d %e\n", i++, f);
}
fclose(inf);
printf("%d floats read.\n", i);

我使用Matlab和访问visa32.dll通过GPIB连接从仪器读取数据。我的读数是数字的。 '> ret = 35 51 49 50 56 82 202 86 51 51 184 86 51> 58 188 86 51 156 195 86 51 145 189 86 51 71 196> 86 51 .... 对于所有其他仪器,简单地使用'char(ret)'% Matlab即可将读数转换为实际数据。然而,从该仪器读取的数据被转换为上述字符串形式。 - uhnucross
使用一个简单的GPIB Spy程序,我可以获得实际的ASCII读数:> ret = R.V33.V3:.V3..V3..V3G.V3A.V3..V3..V3A.V3..V36.V3A.V36.V3..V3:.V3..V3..V3..V3..V3‌​..V3..V36.V3..V3D.V3A.V3..V33.V3..V3=.V3..V33.V3。使用您提供的代码,我得到了以下结果:0 4.986789e-08 1 4.986778e-08 2 4.986780e-08 3 4.986776e-08 4 4.986776e-08 这个结果很有意义,也是我正在寻找的实际数据。非常感谢您的帮助。但是,在Matlab中我不能使用'printf('%e\n',ret(i))',因为它会逐个转换ASCII字符。 - uhnucross
还有一个问题,请问。 在这种情况下,我需要将4个字节转换为长整型-6位精度。 我可以以15位精度读取我的数据,但我需要将8个字节转换为双精度。 在“printf”中,8个字节读取的指示符是什么? 谢谢! - uhnucross
要打印“double”,请将“%e”、“%f”或“%g”中添加“l”。例如:printf(“%lf”,...); - chux - Reinstate Monica
顺便提一下:避免称呼你读取的字节为“ASCII”。 “ASCII”是针对字节值0-127进行定义,但不适用于字节值128-255。 你的ìÀV3é¾...不是ASCII字符串。它不是ASCII,因为它有在ASCII范围之外的字符,比如À。它也不是一个典型的字符串,因为你的字节流中可能嵌入了NUL字节,并且可能没有终止的NUL字节。更好的叫法是将其称为字节数组。祝你好运! - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接