struct模块需严格匹配C结构体的字节序、对齐和类型大小;格式字符串如'i''h''f'对应C的int/short/float,'10s'对应char[10],须显式处理padding(如'xxx')和字节序前缀('>'或'<'),并用calcsize校验长度。

struct 模块能准确对应 C 结构体的内存布局,但必须严格匹配字节序、对齐和类型大小,否则解包结果完全错误。
struct.pack() 和 struct.unpack() 的格式字符串怎么写才对
格式字符串不是随意拼的,它直接映射 C 类型:比如 'i' 对应 int(通常 4 字节),'h' 对应 short(2 字节),'f' 对应 float(4 字节)。C 中的 char[10] 要写成 '10s',末尾的 b'\x00' 会保留,解包后得用 .rstrip(b'\x00') 处理。
常见错误是忽略平台默认字节序:不显式指定时,struct.pack('i', 1) 在 x86_64 Linux 上是小端,但嵌入式设备可能用大端。必须加前缀:'<i>(小端)、<code>'>i'(大端)、'=i'(本机字节序,不推荐用于跨平台)。
- 结构体含指针?不能打包——
struct只处理值,不处理地址 - C 中的
long在不同平台可能是 4 或 8 字节,Python 里用'l'风险高,建议改用'q'(long long,固定 8 字节)或明确注释平台假设 - 字符串字段要预留足够长度,
'8s'解包出来是 bytes,不是 str
如何处理 C 结构体里的内存对齐(padding)
C 编译器会在结构体字段间插入 padding 字节以满足对齐要求,而 struct 默认不自动处理这个。例如:
立即学习“Python免费学习笔记(深入)”;
typedef struct {<br> char a;<br> int b;<br>} test_t;在 GCC x86_64 下实际大小是 8 字节(a 占 1 字节,后面 pad 3 字节,b 占 4 字节),不是 5 字节。如果只写 'ci',struct.calcsize('ci') 返回 5,会导致后续字段全部错位。
正确做法是显式加入 padding:'cxxxi'('x' 表示 1 字节填充),或者用 'BxxxI' 更清晰(B 是无符号 char,I 是无符号 int)。也可以用 struct.calcsize() 校验:struct.calcsize('BxxxI') == 8 才匹配 C 端输出。
- 用
#pragma pack(1)关闭 C 端对齐?可以,但需双方约定,且可能影响性能 - 不确定 padding 布局?用
offsetof和sizeof在 C 侧打印各字段偏移和总大小,再反推 Python 格式串
解包时遇到 struct.error: unpack requires a buffer of X bytes 怎么办
这几乎总是因为数据长度和格式字符串预期不一致。不是“数据少了”,而是 len(data) ≠ struct.calcsize(fmt)。尤其注意:
- 网络接收或文件读取可能只拿到部分数据,需确保完整读够
struct.calcsize(fmt)字节再解包 - C 端用
sizeof(struct)发送,但 Python 用'ci'计算出 5 字节,而实际结构体因对齐占 8 字节 → 必须同步格式串 - 字符串字段末尾有多个
\x00,但'10s'严格要求 10 字节;若 C 端只写入 3 字符+1\x00,剩下 6 字节是未初始化垃圾 → 解包仍成功,但内容不可靠
调试建议:先用 print(repr(data)) 看原始字节,再用 struct.calcsize(fmt) 核对长度,最后逐字段尝试短格式串(如先解前 4 字节)定位错位点。
struct.unpack_from() 比 unpack() 更适合解析连续结构体数组
当二进制数据里是一连串相同结构体(比如 C 的 struct msg arr[100];),用 struct.unpack() 要反复切片,容易出错。直接用 struct.unpack_from(fmt, data, offset) 更稳:
fmt = '<BxxxI' # 匹配上面的 test_t<br>offset = 0<br>for i in range(100):<br> a, b = struct.unpack_from(fmt, data, offset)<br> offset += struct.calcsize(fmt)
好处是不用手动管理切片边界,也不怕 data[offset:offset+N] 越界(unpack_from 会抛异常,而切片可能静默返回短数据)。
- 嵌套结构体?
struct不支持嵌套格式,得拆成多个unpack_from调用,按 C 端字段顺序依次解析 - 字段很多时,用
namedtuple或dataclass封装返回值,别直接用 tuple 下标访问,易错且难维护
最常被忽略的是:C 端结构体定义和 Python 格式串必须由同一份文档或自动生成脚本保证一致,手写两遍必然出错。哪怕只是改了个字段顺序,整个二进制协议就废了。


















