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:
CodeBlock Loading...
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:
CodeBlock Loading...Pack a little-endian struct with padding (e.g.,
int + char, 4-byte alignment):CodeBlock Loading...Pack a fixed-length string:
CodeBlock Loading...Pack a boolean plus an unsigned short (network order):
CodeBlock Loading...
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:
CodeBlock Loading...
- 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