Skip to main content

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 1 over a raw TCP socket to a server. On the receiving end, the server reads the value not as 1, but as 16,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: 01Β 00Β 00Β 00\mathbf{01}\ 00\ 00\ 00
  • 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 01 as the highest-order byte: 0x0100000016=1Γ—224=16,777,2160x01000000_{16} = 1 \times 2^{24} = \mathbf{16{,}777{,}216}

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​

DimensionLittle-EndianBig-Endian (Network Byte Order)
Byte Storage RuleLeast Significant Byte firstMost Significant Byte first
Value 0x12345678 in RAM78 56 34 1212 34 56 78 (Natural human order)
Primary Architecturesx86-64, AMD64, ARM (default)IBM PowerPC, SPARC, Mainframes
Hardware BenefitTypecasting low-order bytes is zero-costIntuitive debug print inspection
Network Protocol StandardUsed in USB and PCI busesMandated for TCP, UDP, IP headers

πŸ’‘ What Interviewers Ask Next (Follow-Up Traps)​

  1. "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);
  2. "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.

Placement & Interview Takeaway

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 (1Γ—2241 \times 2^{24}).


πŸ“Ί Video Explanation​

πŸš€ Level Up Your Engineering Mindset

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
Official Hub

Discord Community

Start at #welcome-and-rules, say hello in #general-chat, clear doubts, and collaborate with engineers worldwide.

Join Discord Server→
⚑
Daily Knowledge Drops

Daily Visual Deep-Dives

Bite-sized system design schematics, core OS internals, and DSA intuition served right into your feeds every single day.

πŸ’‘Have handwritten notes, cheat-sheets, or want to publish a technical article?
Learn How to Contribute→