从二进制文件读取并转换为double?

sim*_*556 2 c file-io file binary-data

我正在尝试编写一个读取二进制文件并将其转换为数据类型的C程序.我正在使用head命令生成二进制文件head -c 40000 /dev/urandom > data40.bin.该程序适用于数据类型int和char但不适用于double.这是该程序的代码.

void double_funct(int readFrom, int writeTo){
    double buffer[150];
    int a = read(readFrom,buffer,sizeof(double));
    while(a!=0){
        int size = 1;
        int c=0;

         for(c=0;c<size;c++){
            char temp[100];
            int x = snprintf(temp,100,"%f ", buffer[c]);
            write(writeTo, temp, x);
        }
        a = read(readFrom,buffer,sizeof(double));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的char函数

void char_funct(int readFrom, int writeTo){
    char buffer[150];
    int a = read(readFrom,buffer,sizeof(char));
    while(a!=0){
        int size = 1;
        int c=0;

        for(c=0;c<size;c++){
            char temp[100]=" ";
            snprintf(temp,100,"%d ", buffer[c]);
            write(writeTo, temp, strlen(temp));
        }
        a = read(readFrom,buffer,sizeof(char));
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,使用char我需要获得40000个单词wc -w file并且我得到它们.现在有了双倍,我得到随机数量的单词但理论上我应该从40000字节的数据得到5000但是我得到4000到15000之间的随机量,对于char我得到40000就像它应该1个字节的一个字符.

我不知道有什么问题,相同的代码适用于int从40000字节的数据中获取10000字的地方.

Joh*_*ger 5

主要问题似乎是您的temp数组对于printf格式和数据来说不够大.IEEE-754 double的小数指数范围从-308到+308.您使用格式打印双打"%f",生成简单的十进制表示.由于未指定精度,因此默认精度为6.这可能需要多达1(符号)+ 309(数字)+ 1(小数点)+ 6(尾随小数位)+ 1(终结符)字符(总共318),但您只有100的空间.

您使用打印到缓冲区snprintf(),因此不会超出那里的数组边界,但snprintf()返回所需的字节数,减去终结符所需的字节数.这是你的字节数write(),在很多情况下超出你的缓冲区.您在输出中看到结果.

其次,您还会0.00000在输出中看到大量的数据,这些数字来自将小数字舍入到6位小数位的精度.

如果更改打印数字的格式,则可能会获得更好的成功.例如,"%.16e "将为您提供指数格式的输出,总共有17位有效数字(小数点前一位).这不需要内存或磁盘上的过多空间,它将准确地传达所有数字,无论规模如何,再次假设您的doubles代表IEEE 754.如果您愿意,您可以进一步消除(相当安全)的假设IEEE 754格式采用@chux在评论中提出的变体.那将是最安全的方法.

还有一件事:IEEE浮点支持无穷大和多个非数值.相对于普通的FP数字,它们的数量非常少,但是你偶尔会遇到其中一个.它们可能会很好地转换为输出,但您可能需要考虑是否需要专门处理它们.

  • `"%.15e"`很好,但不足以打印一些不同的`double`作为不同的文本.建议`printf("%.*e \n",DBL_DECIMAL_DIG - 1,buffer [c]);`以不同方式打印所有不同的`double`.或者`printf("%a \n",buffer [c]);` (3认同)