c – 为什么会乱码我的字节顺序?

前端之家收集整理的这篇文章主要介绍了c – 为什么会乱码我的字节顺序?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图用fread()解析一个bmp文件,当我开始解析时,它会颠倒我的字节顺序.
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(& header,14,1,fileIn)将十六进制数据加载到结构体中;

我的问题是魔术数字应该是0x424d //’BM’fread()它将字节翻转为0x4d42 //’MB’

为什么fread()这样做,我该如何解决它?

编辑:如果我不够详细,我需要将十六进制数据的大部分读入结构体,而不仅仅是魔术数字.我只是选择魔术数字为例.

解决方法

这不是fread的错误,而是你的cpu,这是(显然是)little-endian的.也就是说,您的cpu将第一个字节视为低8位,而不是(如您所期望的那样)高8位.

每当您读取二进制文件格式时,必须将文件格式的字节顺序显式转换为cpu的本机字节.你这样做的功能如下:

/* 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结构体,并根据需要进行转换.这样会看起来像这样:

/* 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,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的字节与文件格式是一样的,即使你知道一个事实,现在他们是一样的;您无论如何都会编写转换,以便将来您的代码将在没有修改的情况下在具有相反字节顺序的cpu上运行.

您可以使用固定宽度的< stdint.h>为自己的生活更轻松类型,通过使用无符号类型,除非能够表示负数是绝对必需的,并且在字符数组将不使用整数时.我在上面的例子中做了这些事情.你可以看到,你不需要打扰字符串转换魔术数字,因为你唯一需要做的就是测试magic_number [0] ==’B’&&& MAGIC_NUMBER [1] == ‘M’.

相反方向的转换btw如下所示:

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位数字的转换作为一项练习.

猜你在找的C&C++相关文章