Why Sending 1 Reads as 16,777,216 Over Sockets (Endianness)
π― The Questionβ
"You write a C program where a client sends a 32-bit integer
1over a raw TCP socket to a server. On the receiving end, the server reads the value not as1, but as16,777,216! Why does this happen, and how do socket APIs resolve it?"
β‘ 30-Second Elevator Pitchβ
This classic networking bug is caused by Endianness (Byte Ordering in RAM):
- Little-Endian (x86 & ARM Desktop/Mobile CPUs):
Stores the Least Significant Byte (LSB) at the lowest memory address.
The 32-bit integer
1(0x00000001) is stored in RAM as: - Big-Endian / Network Byte Order (TCP/IP Standard):
Transmits the Most Significant Byte (MSB) first over the wire.
If sent directly without byte swapping, the receiver reads the first byte
01as the highest-order byte:
The Socket Standard: All multi-byte integers sent over TCP/IP must be converted to Network Byte Order using standard library functions: htonl() (Host-to-Network-Long) on write, and ntohl() (Network-to-Host-Long) on read.
π§ Under-the-Hood: Little-Endian vs. Big-Endian Byte Layoutβ
π¬ The Standard Conversion APIβ
To write portable network code that runs safely across both Big-Endian and Little-Endian architectures, POSIX provides standard byte-swapping functions:
#include <arpa/inet.h>
// On Sender (Host to Network):
uint32_t val = 1;
uint32_t network_val = htonl(val); // Swaps bytes on x86; no-op on Big-Endian
send(sock, &network_val, sizeof(network_val), 0);
// On Receiver (Network to Host):
uint32_t received_val;
recv(sock, &received_val, sizeof(received_val), 0);
uint32_t host_val = ntohl(received_val); // Restores integer to 1 β
π Comparison Matrix: Little-Endian vs. Big-Endianβ
| Dimension | Little-Endian | Big-Endian (Network Byte Order) |
|---|---|---|
| Byte Storage Rule | Least Significant Byte first | Most Significant Byte first |
Value 0x12345678 in RAM | 78 56 34 12 | 12 34 56 78 (Natural human order) |
| Primary Architectures | x86-64, AMD64, ARM (default) | IBM PowerPC, SPARC, Mainframes |
| Hardware Benefit | Typecasting low-order bytes is zero-cost | Intuitive debug print inspection |
| Network Protocol Standard | Used in USB and PCI buses | Mandated for TCP, UDP, IP headers |
π‘ What Interviewers Ask Next (Follow-Up Traps)β
-
"How can you write a 2-line C program to check whether the current CPU is Little-Endian or Big-Endian?"
- Answer: Inspect the first byte of a multi-byte integer:
int n = 1;
bool is_little_endian = (*(char*)&n == 1);
- Answer: Inspect the first byte of a multi-byte integer:
-
"Why do modern serialization formats like Protocol Buffers and JSON avoid endianness bugs?"
- Answer: Text formats like JSON serialize numbers into ASCII strings (
"1"), which are arrays of single bytes that have no multi-byte endianness. Binary formats like Protobuf explicitly specify little-endian varints in their wire specification, ensuring cross-platform consistency.
- Answer: Text formats like JSON serialize numbers into ASCII strings (
Interview Answer: Sending 1 reads as 16,777,216 because of an Endianness mismatch. x86 CPUs use Little-Endian (storing 0x01 00 00 00), whereas TCP/IP protocols expect Big-Endian Network Byte Order. Without converting using htonl() and ntohl(), the first byte is interpreted as the most significant byte ().
πΊ Video Explanationβ
Never Study in Isolation. Join Binary Dose.
Connect with fellow engineers, clear conceptual doubts, and get 2 visual breakdowns & engineering mental models daily across our community channels.
Discord Community
Start at #welcome-and-rules, say hello in #general-chat, clear doubts, and collaborate with engineers worldwide.