Choose explicit byte order to avoid native struct padding
Also published in our primary archive.
Choose explicit byte order to avoid native struct padding
For an exchanged binary record, give struct an explicit standard-format prefix such as !; do not assume native @BI is a five-byte wire layout. !BI means one unsigned byte followed by one big-endian, standard-size unsigned integer, with no automatic alignment padding.
This experiment compares the two formats for B=1 and I=0x02030405. Native mode (@) inherits the platform's byte order, C type sizes, and alignment rules. Its calcsize result is therefore deliberately treated as platform-dependent. The code only asserts that it can hold the five field bytes; it does not assert an exact native size or print a machine-specific value.
The correction defines a protocol format, !BI, and checks its size before packing. Its exact size is five bytes, and its bytes are 01 02 03 04 05. The unpack assertion confirms that this specific fixture round-trips under the chosen format. It does not establish compatibility with another application's schema: both sides still need to agree on field order, integer ranges, versioning, and any framing around records.
struct.calcsize() and struct.pack() are long-standing standard-library APIs; no newer API is required. The ! prefix is network byte order, which is big-endian with standard sizes and no alignment. See the Python struct documentation.
AI assistance disclosure: this article was drafted with AI assistance and its synthetic example was checked for deterministic output.
from struct import calcsize, pack, unpack
native_format = "@BI"
wire_format = "!BI"
kind = 1
number = 0x02030405
native_size = calcsize(native_format)
wire_size = calcsize(wire_format)
wire_bytes = pack(wire_format, kind, number)
# Native size can vary with the interpreter platform and C alignment rules.
assert native_size >= 5
assert wire_size == 5
assert wire_bytes == b"\x01\x02\x03\x04\x05"
assert unpack(wire_format, wire_bytes) == (kind, number)
print("native size: platform-dependent")
print("wire size:", wire_size)
print("wire bytes:", wire_bytes)
native size: platform-dependent
wire size: 5
wire bytes: b'\x01\x02\x03\x04\x05'