为什么FREAD惹我的字节顺序? [英] Why does fread mess with my byte order?

查看:150
本文介绍了为什么FREAD惹我的字节顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着解析一个bmp文件 FREAD(),当我开始解析,它颠倒了我的字节顺序。

Im trying to parse a bmp file with fread() and when I begin to parse, it reverses the order of my bytes.

typedef struct{
    short magic_number;
    int file_size;
    short reserved_bytes[2];
    int data_offset;
}BMPHeader;
    ...
BMPHeader header;
    ...

十六进制数据是 42 4D 36 00 03 00 00 00 00 00 36 00 00 00 ;
我对 FREAD装载十六进制数据到结构(安培;头,14,1,FILEIN);

我的问题就是一个神奇的数字应该是 0x424d //BM FREAD()它翻转字节是覆盖0x4D42 // MB

My problem is where the magic number should be 0x424d //'BM' fread() it flips the bytes to be 0x4d42 // 'MB'

为什么FREAD()做到这一点,我怎么能解决这个问题;

Why does fread() do this and how can I fix it;

编辑:如果我是不够具体,我需要阅读十六进制数据的整个块到结构不只是一个神奇的数字。我只挑一个神奇的数字,例如,

If I wasn't specific enough, I need to read the whole chunk of hex data into the struct not just the magic number. I only picked the magic number as an example.

推荐答案

这是不是 FREAD ,但你的CPU,这是(显然)的故障little-尾数。也就是说,你的CPU在值作为的的8位,而不是(因为你似乎已经预期)在治疗的第一个字节高8位。

This is not the fault of fread, but of your CPU, which is (apparently) little-endian. That is, your CPU treats the first byte in a short value as the low 8 bits, rather than (as you seem to have expected) the high 8 bits.

当你读一个二进制文件格式,你必须明确地从文件格式的字节序到CPU的本地字节序转换。你这样做,有了这样的功能:

Whenever you read a binary file format, you must explicitly convert from the file format's endianness to the CPU's native endianness. You do that with functions like these:

/* CHAR_BIT == 8 assumed */
uint16_t le16_to_cpu(const uint8_t *buf)
{
   return ((uint16_t)buf[0]) | (((uint16_t)buf[1]) << 8);
}
uint16_t be16_to_cpu(const uint8_t *buf)
{
   return ((uint16_t)buf[1]) | (((uint16_t)buf[0]) << 8);
}

您做你的 FREAD 成适当大小的 uint8_t有缓冲区,然后手动复制所有数据字节到你的 BMPHeader 结构,转换是必要的。这将是这个样子:

You do your fread into an uint8_t buffer of the appropriate size, and then you manually copy all the data bytes over to your BMPHeader struct, converting as necessary. That would look something like this:

/* note adjustments to type definition */
typedef struct BMPHeader
{
    uint8_t magic_number[2];
    uint32_t file_size;
    uint8_t reserved[4];
    uint32_t data_offset;
} BMPHeader;

/* in general this is _not_ equal to sizeof(BMPHeader) */
#define BMP_WIRE_HDR_LEN (2 + 4 + 4 + 4)

/* returns 0=success, -1=error */
int read_bmp_header(BMPHeader *hdr, FILE *fp)
{
    uint8_t buf[BMP_WIRE_HDR_LEN];

    if (fread(buf, 1, sizeof buf, fp) != sizeof buf)
        return -1;

    hdr->magic_number[0] = buf[0];
    hdr->magic_number[1] = buf[1];

    hdr->file_size = le32_to_cpu(buf+2);

    hdr->reserved[0] = buf[6];
    hdr->reserved[1] = buf[7];
    hdr->reserved[2] = buf[8];
    hdr->reserved[3] = buf[9];

    hdr->data_offset = le32_to_cpu(buf+10);

    return 0;
}

您做的的假设CPU的字节顺序是一样的文件格式的即使的你知道一个事实,现在他们是相同的;你写的转换,无论如何,让您在未来的code无需修改工作,与对面的字节顺序在CPU上。

You do not assume that the CPU's endianness is the same as the file format's even if you know for a fact that right now they are the same; you write the conversions anyway, so that in the future your code will work without modification on a CPU with the opposite endianness.

您可以通过使用固定宽度使生活为自己容易&LT; stdint.h&GT; 类型,使用无符号类型,除非能够重新present负数是绝对必要的,并且通过的的使用整数时,字符数组就行了。我已经做了所有这些东西在上面的例子中。你可以看到,不用您费心端转换一个神奇的数字,因为你需要用它做的唯一事情是测试 MAGIC_NUMBER [0] =='B'和;&安培; MAGIC_NUMBER [1] =='M'

You can make life easier for yourself by using the fixed-width <stdint.h> types, by using unsigned types unless being able to represent negative numbers is absolutely required, and by not using integers when character arrays will do. I've done all these things in the above example. You can see that you need not bother endian-converting the magic number, because the only thing you need to do with it is test magic_number[0]=='B' && magic_number[1]=='M'.

转换相反的方向,顺便说一句,看起来是这样的:

Conversion in the opposite direction, btw, looks like this:

void cpu_to_le16(uint8_t *buf, uint16_t val)
{
   buf[0] = (val & 0x00FF);
   buf[1] = (val & 0xFF00) >> 8;
}
void cpu_to_be16(uint8_t *buf, uint16_t val)
{
   buf[0] = (val & 0xFF00) >> 8;
   buf[1] = (val & 0x00FF);
}

32的/ 64位值转换留作练习。

Conversion of 32-/64-bit quantities left as an exercise.

这篇关于为什么FREAD惹我的字节顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆