我正在尝试编写一个C程序,该程序读取二进制文件并将其转换为数据类型。我正在使用头命令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));
    }
}

这是有效的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));
    }
}

问题是使用char我需要使用wc -w file获得40000个单词,然后我将它们获得。现在有了double我得到了随机的单词数量,但理论上我应该从40000字节的数据中得到5000,但是我得到4000到15000之间的随机数,对于char我得到40000,就像它应该为一个字符提供1个字节。

我不知道这是什么问题,相同的代码适用于int,其中我从40000字节的数据中获得10000个单词。

最佳答案

主要问题似乎是您的temp数组不足以容纳您的printf格式和数据。 IEEE-754 double的十进制指数范围是-308至+308。您正在使用"%f"格式打印双打,它会生成普通的十进制表示形式。由于未指定精度,因此默认精度为6。这可能需要多达1(符号)+ 309(数字)+1(小数点)+6(尾随小数位)+1(终止符)字符(总共318个字符),但是您只能容纳100个空间。

您使用snprintf()打印到缓冲区,因此不会超出那里的数组范围,但是snprintf()返回所需的字节数,减去终止符所需的字节数。那就是你write()的字节数,并且在许多情况下确实超出了缓冲区。您会在输出中看到结果。

其次,您还会在输出中看到大量的0.00000,这是由于将小数舍入到6位小数位数而引起的。

如果更改打印数字的格式,可能会获得更好的成功。例如,"%.16e "将为您提供指数格式的输出,总共有17个有效数字(小数点前一位)。再次假设您的double是根据IEEE 754表示的,那将不需要在内存或磁盘上占用过多的空间,并且它将准确地传递所有数字,而不管其规模如何。如果您愿意,还可以消除(非常安全的)假设通过使用@chux在注释中建议的变体来更改IEEE 754格式。那将是最安全的方法。

还有一件事:IEEE浮点支持无限性和多个非数字值。与普通FP编号相比,这些编号的数量很少,但是您偶尔还是会碰到其中之一。它们可能会被转换为输出,但是您可能要考虑是否需要专门处理它们。

09-25 23:10