Little-Endian vs Big-Endian in C Programming

In the C programming language, multi-byte integers are stored in memory across consecutive byte addresses using either little-endian or big-endian ordering, determined by the underlying hardware architecture. This article explains the fundamental differences between these two memory representations, illustrates how integer words are arranged in memory addresses, and demonstrates how to check or handle byte ordering in C code.

The Concept of Endianness

A standard 32-bit integer word consists of four bytes. For example, the hexadecimal integer value 0x12345678 is made up of four individual bytes: 0x12 (the Most Significant Byte, or MSB), 0x34, 0x56, and 0x78 (the Least Significant Byte, or LSB).

Endianness defines the sequential order in which these bytes are mapped to increasing memory addresses. The C language standard does not mandate a specific byte order; instead, it delegates this choice to the target CPU architecture.

Big-Endian Representation

In big-endian representation, the Most Significant Byte is stored at the lowest (first) memory address, while the Least Significant Byte is stored at the highest address. This matches the standard left-to-right reading order of numbers.

Using the value 0x12345678 stored at base address 0x1000:

  • 0x1000: 0x12 (MSB)
  • 0x1001: 0x34
  • 0x1002: 0x56
  • 0x1003: 0x78 (LSB)

Big-endian is commonly referred to as "network byte order" because Internet protocols (such as IP and TCP) standardize on this format. It was also historically common on architectures such as SPARC, Motorola 68000, and older PowerPC chips.

Little-Endian Representation

In little-endian representation, the Least Significant Byte is stored at the lowest (first) memory address, and the Most Significant Byte is stored at the highest address.

Using the same value 0x12345678 stored at base address 0x1000:

  • 0x1000: 0x78 (LSB)
  • 0x1001: 0x56
  • 0x1002: 0x34
  • 0x1003: 0x12 (MSB)

Little-endian is the dominant layout in modern consumer computing, used by x86, x86-64, and the default configurations of ARM processors.

Detecting Endianness in C

Because C allows low-level memory inspection via pointers and type punning, you can determine the endianness of the current system at runtime by examining the byte stored at the base address of an integer:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint32_t value = 0x01;
    uint8_t *byte_ptr = (uint8_t *)&value;

    if (*byte_ptr == 0x01) {
        printf("System is Little-Endian\n");
    } else {
        printf("System is Big-Endian\n");
    }

    return 0;
}

In this code, if the first byte accessed via byte_ptr contains 0x01, the least significant byte is stored first, confirming a little-endian machine.

Practical Implications in C

Understanding endianness is critical in two main areas of C software development:

  1. Network Communication: Since network protocols mandate big-endian ordering, systems running on little-endian architectures must convert integer words using POSIX functions such as htonl() (host to network long) and ntohl() (network to host long) before sending and after receiving data.
  2. Binary File Formats: When reading or writing raw binary data (such as image files, audio, or database records) across different architectures, endian-independent code must explicitly serialize and deserialize integer fields rather than using direct fread() or fwrite() operations into integer pointers.