写入二进制文件前必须显式处理内存对齐,否则因编译器填充字节导致数据错乱;应禁用对齐(如#pragma pack(1))或手动序列化,并注意字节序、类型符号性及POD限制。
直接用 write() 把 struct 原样写入文件,读出来大概率出错——不是数据错位,就是字段值完全不对。根本原因是编译器为提升访问速度,在 struct 成员间插入填充字节(padding),而这些字节内容未定义,写入后破坏了数据一致性。
常见错误现象:sizeof(MyStruct) 比各成员 sizeof 之和大;跨平台读取时字段偏移错乱;用 memcpy 拷贝到 buffer 后再 write,仍无法被其他语言或旧版本程序正确解析。
#pragma pack(1))最直接,但会降低访问性能,仅适用于 IO 场景write(),跳过 padding,明确控制字节顺序和长度#pragma pack(1) 是最常用、见效最快的方案,但它有陷阱,不是加一行就万事大吉。
使用场景:协议固定、结构简单、不频繁访问字段(如日志快照、配置缓存、游戏存档)。
struct 定义前,且需配对使用 #pragma pack() 恢复默认,避免污染后续声明#pragma pack 支持一致,但 Clang/GCC/MSVC 对嵌套 struct 的处理略有差异,建议统一用 __attribute__((packed))(GCC/Clang)或 __declspec(align(1))(MSVC)作补充校验offsetof 和指针运算依然有效,但 CPU 访问未对齐地址可能触发异常(尤其 ARM 架构),所以仅用于写入/读取,别在运行时高频解引用struct __attribute__((packed)) Header {
uint32_t magic;
uint16_t version;
uint8_t flags;
};
// sizeof(Header) == 7,无填充
即使 struct 对齐了,write() 出来的二进制仍是本机字节序,且 char 默认有符号性。这两点在跨平台或与 Python/Java 交互时极易翻车。
典型错误:Windows 上写的 int32_t,Linux 上读成负数;C++ 里 char data[4] 存 0xFF,Py

struct.unpack('B', ...) 解出 255,但用 'b' 却得 -1。
uint8_t / int32_t 等明确宽度和符号性的类型,避开 int、long、char
htons()/htonl() 或 bswap_32() 转换后再 writestd::string::c_str(),要 write data().data() + size(),并约定是否含 '\0'很多代码图省事,分配 buffer 后 reinterpret_cast 就开始读字段——这在 #pragma pack(1) 下看似可行,但一旦 struct 含 std::string、std::vector 或虚函数,立刻 UB(未定义行为)。
真实风险:对象内有指针成员(如 char*),反序列化后指向无效地址;移动构造/拷贝构造未被调用,资源未初始化;vtable 指针错乱导致 crash。
std::is_trivially_copyable_v 编译期断言uint8_t 数组,再用参数构造对象对齐这事,表面是 #pragma pack 一行的事,背后牵扯 ABI、CPU 架构、类型系统和序列化契约。最容易被忽略的是:你以为写进去的是数据,其实写进去的是“编译器和你之间的临时约定”,而文件得活十年以上——那个约定早就不作数了。