Advanced

Byte order

A number bigger than a byte is stored as several bytes. The order those bytes are written in is called endianness, and two orders mean the same bytes read as two numbers.

What you will see

256

About 2 min of reading

Try It

Read bytes in both orders.

1

Read four bytes big-endian.

import struct print(struct.unpack(">I", b"\x00\x00\x01\x00")[0])

Before you run it, say out loud what it will print. Then open the answer.

What it prints
256
2

Read the same four bytes little-endian.

import struct print(struct.unpack("

Before you run it, say out loud what it will print. Then open the answer.

What it prints
16777216
3

Pack big and unpack little to see the swap.

import struct print(struct.unpack("H", 256))[0])

Before you run it, say out loud what it will print. Then open the answer.

What it prints
1
The bytes were written one way and read the other, so 256 becomes 1.
4

Swap a value to network order.

import socket print(socket.htons(1))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
256

Data Flow

A multi-byte number is stored as bytes in one of two orders, and reading with the wrong order gives a wrong number.
1 number needs several bytes
↓
2 big-endian or little-endian
↓
3 same bytes two numbers
↓
4 wrong order swaps them
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

import struct sets nothing on screen
print(struct.unpack(">I", b"\x00\x00\x01\x00")[0]) 256
Why this works
Order is a property of the format

A file or protocol states its byte order. Reading it with the wrong order is not a crash, it is a wrong number, which is why it is easy to miss.

Know your machine

Most modern computers are little-endian. Formats are often big-endian. The gap between the two is where byte-order bugs come from.

Examples

Two orders

import struct
print(struct.unpack(">I", b"\x00\x00\x01\x00")[0])
print(struct.unpack("<I", b"\x00\x00\x01\x00")[0])

The same four bytes read big-endian and little-endian give different numbers. The bytes are identical.

Big and little

import struct
print(struct.pack(">H", 256))
print(struct.pack("<H", 256))

Big-endian writes the big end first, little-endian the small end first. Most formats say which they use.

Why it bites

import struct
print(struct.unpack("<H", struct.pack(">H", 256))[0])

Packing big and unpacking little swaps the bytes, so 256 comes back as 1. That is a byte-order bug.

The network is big

import socket
print(socket.htons(1))

Network formats are big-endian, so a little-endian machine swaps on send. The helper functions do that swap for you.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Encodings and why they differ
Previous Lesson
Encodings and why they differ
Next Lesson
Packing values into bytes
Packing values into bytes →