Single bytes in hex are easy: 4A is one value. Trouble starts at 16-bit, 32-bit, and 64-bit integers written as hex. The same digits mean different numbers depending on which byte is first—endianness.
IP addresses are one special case (IPv4/IPv6 hex). This article covers the general integer case you meet in file formats, binary protocols, and language pack/struct APIs.
Big-endian vs little-endian
Number: 0x12345678
Big-endian bytes: 12 34 56 78
Little-endian bytes: 78 56 34 12
- Big-endian (network order): most significant byte first. Common on the wire.
- Little-endian: least significant byte first. Common on x86/x64 hosts.
If you reverse the byte order by mistake, you still get a “valid” integer—just the wrong one.
Reading widths from a dump
- Know the field width (u16 / u32 / u64).
- Know the endianness from the format spec.
- Slice that many bytes from the correct offset.
- Assemble with shifts or a structured unpacker.
import struct
data = bytes.fromhex("12345678")
print(struct.unpack(">I", data)[0]) # 305419896 big-endian
print(struct.unpack("<I", data)[0]) # 2018915346 little-endian
<?php
$bin = hex2bin("12345678");
$be = unpack("N", $bin)[1]; // unsigned long big-endian
$le = unpack("V", $bin)[1]; // unsigned long little-endian
PHP pack/unpack letters matter—see pack() guide.
Where teams get hurt
- Copying hex from a debugger that already displays host endianness, then treating it as wire order.
- Documenting examples without stating endianness.
- Mixing
uint32_tcasts with byte arrays on different CPUs. - Assuming “hex order on screen” equals “memory order.”
Practical habit
Write the endianness next to every multi-byte hex example in your docs:
length = 0x00000100 (u32 BE) → bytes 00 00 01 00
length = 0x00000100 (u32 LE) → bytes 00 01 00 00
Floating point and other layouts
IEEE-754 floats also have endian concerns when stored as raw bytes. Do not reinterpret float hex with integer rules. Use language APIs that pack floats explicitly.
Checklist before you ship a binary parser
- Unit-test both endiannesses with known vectors.
- Reject buffers shorter than the field width.
- Log fields as
value=0x... (bytes=...)during bring-up. - Freeze endianness in the spec; do not “auto-detect” without a magic discriminator.
def u32_be(b: bytes, off: int = 0) -> int:
return int.from_bytes(b[off:off+4], "big")
def u32_le(b: bytes, off: int = 0) -> int:
return int.from_bytes(b[off:off+4], "little")
FAQ
Is network order always big-endian?
For classic Internet protocols, yes. Always read the RFC for custom protocols.
Does hex itself have endianness?
Hex text is just digits. Endianness appears when those digits represent a multi-byte integer layout in memory or on the wire.
How do I convert quickly while debugging?
Use a structured unpack in a REPL, or break the hex into bytes and reverse groups of 2/4/8 digits as needed. Hex Calculator helps with related arithmetic.
Related: reading hex dumps · decode pitfalls · hex overview.