struct.pack 的 fmt 文档
对于十六进制的协议,python 中的编写总是会用到 struct.pack 。各种写法,我根本记不住。例如
struct.pack('>H', checksum)
data = struct.pack('>I', id)
一、字节顺序与对齐(首字符)
格式字符串的第一个字符通常表示字节顺序和对齐方式:
字符 | 说明 | 示例 |
---|---|---|
@ | 默认(本地字节序,无对齐) | @I |
= | 本地字节序,标准大小 | =H |
< | 小端(Little-Endian) | <i |
> | 大端(Big-Endian) | >f |
! | 网络序(等同于大端) | !d |
二、数据类型与大小
字符 | C 类型 | Python 类型 | 大小(字节) | 示例 |
---|---|---|---|---|
x | 填充字节 | 无 | 1 | x |
c | char | 长度为1的字节 | 1 | c |
b | signed char | 整数 | 1 | b |
B | unsigned char | 整数 | 1 | B |
? | _Bool | 布尔值 | 1 | ? |
h | short | 整数 | 2 | h |
H | unsigned short | 整数 | 2 | H |
i | int | 整数 | 4 | i |
I | unsigned int | 整数 | 4 | I |
l | long | 整数 | 4 | l (32位系统) |
L | unsigned long | 整数 | 4 | L (32位系统) |
q | long long | 整数 | 8 | q |
Q | unsigned long long | 整数 | 8 | Q |
f | float | 浮点数 | 4 | f |
d | double | 浮点数 | 8 | d |
s | char[] | 字节串 | 长度由数字前缀指定 | 10s |
p | Pascal字符串 | 字节串 | 长度+1字节(最大255) | p |
P | void* | 整数 | 平台相关 | P |
三、特殊符号
字符 | 说明 | 示例 |
---|---|---|
0 | 填充字节(等同于 x ) | 0x |
num | 数字前缀表示重复次数或长度 | 3I 表示打包3个无符号整型 |
_ | 平台本地大小和对齐(需 Python 3.3+) | _d |
四、常用组合示例
打包一个大端 4 字节无符号整型 + 双精度浮点数:
python data = struct.pack('>Id', 0x1234, 3.14)
打包一个带填充的小端结构体(例如
int + char
,4 字节对齐):python data = struct.pack('<ic', 42, b'A') # 自动填充 1 字节
打包一个固定长度的字符串:
python data = struct.pack('10s', b'hello') # 补零到 10 字节
打包布尔值 + 无符号短整型(网络序):
python data = struct.pack('!?H', True, 0xABCD)
五、注意事项
数值范围验证:
- 例如
B
(0~255)、I
(0~0xFFFFFFFF),超出范围会报错。 建议在打包前检查数值范围:
if not (0 <= value <= 0xFFFF): raise ValueError("数值超出范围")
- 例如
平台差异:
l
和L
在 32 位系统为 4 字节,64 位系统可能为 8 字节。- 使用
i
或I
确保固定 4 字节。
字符串处理:
s
格式需要明确长度(如10s
)。- 若需动态长度字符串,可配合
len()
使用:python s = b'hello' data = struct.pack(f'I{len(s)}s', len(s), s)