fread读取二进制文件后unsigned short缓冲区数据与原格式不符问题
二进制文件读取的字节序问题解析
兄弟,你猜的没错,这个问题完全是字节序(endianess)搞的鬼!咱们一步步拆解来看:
问题根源
你的二进制文件里的2字节数据是按大端字节序存储的:文件中第一个字节是0X(高字节),第二个字节是Y0(低字节),合起来就是你预期的0XY0十六进制值。
但你的系统大概率是小端字节序(绝大多数x86/x86_64架构的电脑都是小端),小端的规则是:内存中低地址存储数据的低字节,高地址存储高字节。当你用unsigned short(2字节类型)读取文件时,fread会把文件里的两个字节直接按内存顺序塞进unsigned short变量:
- 文件第一个字节(
0X)被存在unsigned short的低地址位(对应变量的低字节) - 文件第二个字节(
Y0)被存在unsigned short的高地址位(对应变量的高字节)
组合起来就变成了Y00X,和你预期的刚好反过来。
而用char数组读取没问题,是因为char是单字节类型,fread会严格按文件的字节顺序依次存入数组,不会做任何字节重组,所以完全符合文件里的0XY0顺序。
解决办法
这里给你两个靠谱的方案:
方案1:手动转换字节序
读取完unsigned short数组后,逐个把每个元素的高低字节交换,把小端转成大端:
for (int i = 0; i < bufferSize; i++) { buffer[i] = ((buffer[i] >> 8) | (buffer[i] << 8)); }
如果你的数据是符合网络字节序(大端)的,也可以用标准库的ntohs()函数(network to host short),效果一样:
#include <arpa/inet.h> // 注意引入头文件 for (int i = 0; i < bufferSize; i++) { buffer[i] = ntohs(buffer[i]); }
方案2:用char数组读取后手动组装
继续用char数组读取,然后把两个字节手动组装成unsigned short,这样不管系统字节序是什么,都能得到正确的结果:
char buffer[bufferSize * 2]; // 这里省略fopen和fread的代码... unsigned short result[bufferSize]; for (int i = 0; i < bufferSize; i++) { // 把高字节(buffer[2i])左移8位,再和低字节(buffer[2i+1])按位或 result[i] = ((unsigned char)buffer[2*i] << 8) | (unsigned char)buffer[2*i+1]; }
这里要把char转成unsigned char再操作,避免符号位带来的问题。
内容的提问来源于stack exchange,提问作者Emanuele
相关产品推荐
相关产品推荐

