When working with hex protocols in Python, you always end up using struct.pack. There are so many format variations that I simply can't remember them all. For example:
Python
struct.pack('>H', checksum)
data = struct.pack('>I', id)
1. Byte Order and Alignment (First Character)
The first character of the format string usually indicates byte order and alignment:
| Character | Meaning | Example |
|---|---|---|
@ | Default (native byte order, no alignment) | @I |
= | Native byte order, standard size | =H |
< | Little-Endian | <i |
> | Big-Endian | >f |
! | Network order (equivalent to big-endian) | !d |
2. Data Types and Sizes
| Character | C Type | Python Type | Size (bytes) | Example |
|---|---|---|---|---|
x | Padding byte | None | 1 | x |
c | char | Bytes of length 1 | 1 | c |
b | signed char | Integer | 1 | b |
B | unsigned char | Integer | 1 | B |
? | _Bool | Boolean | 1 | ? |
h | short | Integer | 2 | h |
H | unsigned short | Integer | 2 | H |
i | int | Integer | 4 | i |
I | unsigned int | Integer | 4 | I |
l | long | Integer | 4 | l (32-bit systems) |
L | unsigned long | Integer | 4 | L (32-bit systems) |
q | long long | Integer | 8 | q |
Q | unsigned long long | Integer | 8 | Q |
f | float | Float | 4 | f |
d | double | Float | 8 | d |
s | char[] | Bytes | Specified by numeric prefix | 10s |
p | Pascal string | Bytes | Length + 1 byte (max 255) | p |
P | void* | Integer | Platform-dependent | P |
3. Special Symbols
| Character | Meaning | Example |
|---|---|---|
0 | Padding byte (same as x) | 0x |
num | Numeric prefix indicating repeat count or length | 3I = pack three unsigned integers |
_ | Native platform size and alignment (requires Python 3.3+) | _d |
4. Common Packing Examples
Pack a big-endian 4-byte unsigned integer plus a double-precision float:
Pythondata = struct.pack('>Id', 0x1234, 3.14)Pack a little-endian struct with padding (e.g.,
int + char, 4-byte alignment):Pythondata = struct.pack('<ic', 42, b'A') # 自动填充 1 字节Pack a fixed-length string:
Pythondata = struct.pack('10s', b'hello') # 补零到 10 字节Pack a boolean plus an unsigned short (network order):
Pythondata = struct.pack('!?H', True, 0xABCD)
5. Notes
Value range validation:
- For example,
B(0–255) andI(0–0xFFFFFFFF) raise an error when out of range. It's a good idea to check the value range before packing:
Pythonif not (0 <= value <= 0xFFFF): raise ValueError("数值超出范围")
- For example,
Platform differences:
landLare 4 bytes on 32-bit systems, and may be 8 bytes on 64-bit systems.- Use
iorIto ensure a fixed 4 bytes.
String handling:
- The
sformat requires an explicit length (e.g.,10s). - If you need a dynamic-length string, combine it with
len():python s = b'hello' data = struct.pack(f'I{len(s)}s', len(s), s)
- The
struct.pack fmt Documentation