read/write参数需传缓冲区指针、起始地址和字节数,避免sizeof(buf)错误;返回值须检查;struct直接读写需处理对齐、字节序、版本兼容等问题。

read 和 write 函数的参数到底怎么填
read 和 write 是 C++ 中底层二进制 I/O 的核心函数,但它们不属于 C++ 标准库,而是来自 C 标准库(<unistd.h>),只在 POSIX 系统(Linux/macOS)可用;Windows 上得用 ReadFile/WriteFile 或 fread/fwrite。别一上来就写 read(fd, buf, sizeof(buf)) —— sizeof(buf) 在函数传参后是错的,因为数组退化为指针。
正确做法是显式传入缓冲区长度:
-
read(fd, buffer, buffer_size):第三个参数是字节数,不是元素个数 -
write(fd, data, size):第二个参数必须是const void*,传std::string要用.data()+.size() - 返回值必须检查:
read返回实际读到的字节数(可能小于请求值,也可能为 0 表示 EOF),write同理,且可能只写了一部分
自定义 struct 直接 read/write 会出什么问题
直接把 struct 地址传给 read 或 write 看似方便,但极易踩坑。比如:
struct Person {
int id;
char name[32];
double salary;
};
这种结构体在内存中受对齐填充影响,不同编译器、不同平台的 sizeof(Person) 可能不同;如果跨平台传输或存档,读出来字段全错。
立即学习“C++免费学习笔记(深入)”;
- 必须用
#pragma pack(1)或__attribute__((packed))消除填充(仅限同构环境) - 浮点数二进制表示不跨平台可移植(IEEE 754 虽然主流,但 endianness 和 NaN 处理仍有差异)
- 含指针、虚函数、
std::string、std::vector的类绝对不能直接读写 —— 它们内部是动态分配的,write只拷贝指针值,毫无意义
用 ifstream/ofstream 的 read/write 成员函数更安全吗
是的,C++ 标准流的 read 和 write 成员函数(如 file.read(reinterpret_cast<char*>(&x), sizeof(x)))比 C 的 read/write 更易用,且跨平台。但它没解决本质问题:仍是按内存布局硬拷贝。
- 打开文件必须用
std::ios::binary,否则 Windows 下换行符会被悄悄转换 -
read不自动 null-terminate 字符串,别拿它读 C 风格字符串然后直接printf - 读取后务必检查
gcount()(实际读取字节数)和fail()状态,不要只看eof() - 写入前确保文件处于写模式:
std::ofstream f("data.bin", std::ios::binary | std::ios::out);
真正可靠的二进制序列化该怎么做
绕不开的问题:只要涉及长期存储、网络传输或跨语言交互,裸 read/write 就是技术债。真正的可靠做法是分层处理。
- 用固定大小整型:改用
int32_t、uint64_t替代int、long - 手动序列化字段:逐个
write字段,中间加校验(如字段长度、magic number) - 字节序必须显式处理:网络字节序用
htons/htonl,读时用ntohs/ntohl - 字符串要先写长度再写内容,避免依赖 \0 或固定缓冲区
最常被忽略的一点:二进制格式没有版本号概念。一旦 struct 字段增删,旧程序读新数据直接崩溃 —— 所以哪怕只是实验项目,也得在文件头预留 4 字节版本字段。











