fread读整数错因主要是字节序不匹配或结构体填充差异,应统一用网络字节序并配合bswap转换;读字符串需按协议处理长度和终止符;读结构体仅限POD类型且须保证两端内存布局一致;Windows下必须用"rb"模式。

用 fread 读整数时字节序不匹配,值完全不对
直接 fread(&x, sizeof(int), 1, fp) 得到的值和写入时不一致,大概率是跨平台或跨编译器导致的字节序(endianness)错位。比如 Windows x64 写的 int 是小端,但你用大端机器读,或者结构体里字段对齐方式不同,sizeof(MyStruct) 实际写入长度就和预期不等。
- 确认写入和读取环境的
sizeof(int)、__BYTE_ORDER__是否一致;Linux 可查#include,Windows 无原生宏,得靠_byteswap_ulong - 不要依赖
int的具体大小,改用固定宽度类型:读uint32_t就用fread(&x, sizeof(uint32_t), 1, fp),再手动做ntohl()或bswap_32() - 如果文件由你自己控制生成,统一用网络字节序(大端)写入,读取时统一转回主机序,避免歧义
读字符串时遇到 \0 就截断,内容不全
fread 不认 C 字符串规则,它只按字节数读;但如果你用 char buf[256]; fread(buf, 1, 256, fp); printf("%s", buf);,一旦中间有 \0,printf 就停了——这不是读错了,是输出逻辑错了。
- 字符串在二进制文件中通常有两种存法:定长数组(如
char name[32])或带长度前缀(如uint16_t len; char data[len];),必须和写入协议严格一致 - 读定长字符串后,手动补
\0并限制打印长度:buf[31] = '\0'; printf("%.31s", buf); - 读变长字符串务必先读长度字段,再按该长度分配/读取内存,别硬塞进栈数组,否则容易溢出
用 fread 直接读结构体,字段值全乱码
结构体直接 fread(&s, sizeof(MyStruct), 1, fp) 看似方便,但极易失败:编译器可能加填充字节(padding),#pragma pack(1) 没对齐,或结构体含指针、STL 容器(如 std::string)——这些根本不能二进制序列化。
- 只对 POD(Plain Old Data)类型结构体这么做,且确保写入端也用相同编译选项和
pack设置 - 检查实际内存布局:
offsetof(MyStruct, field)和sizeof(MyStruct),对比写入时的偏移是否一致 - 含
std::string、std::vector的结构体,必须逐字段读:先读长度,再读数据,再resize或assign,不能整体fread
Windows 下读二进制文件忘记用 "rb" 模式
在 Windows 上用 fopen("data.bin", "r") 打开二进制文件,会触发文本模式的换行转换(\r\n → \n),导致后续所有偏移错位,fread 读出来的字节流和原始文件不一致。
- 无论什么平台,读二进制文件一律用
"rb";写则用"wb" - Linux/macOS 对
"r"和"rb"处理一致,但代码跨平台时漏掉b就是隐患 - 打开失败时检查
ferror(fp)和errno,常见错误是EINVAL(非法模式)或ENOENT(路径错)
二进制读取真正难的不是语法,而是两端协议必须咬死:每个字段的字节序、长度、对齐、是否含 padding、字符串怎么界定——差一个字节,后面全崩。别信“结构体直接 fread 就行”,先用 hexdump 看一眼文件实际长啥样。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











