Memory Address Binary

How computer memory addresses work in binary at the hardware level

The Binary Nature of Memory Addresses

In my experience working with low-level systems programming, one concept stands out: every memory address in a computer is fundamentally a binary number. When your CPU reads a byte from RAM, it sends an address over the address bus as a parallel set of electrical signals — each wire carrying either 5V (logical 1) or 0V (logical 0). The number of wires determines how many unique addresses the CPU can reference.

For example, a 32-bit address bus has 32 wires. The address 0x7FFFFFFF (the highest address in a 2 GB range) is sent as the binary pattern 0111_1111_1111_1111_1111_1111_1111_1111 across those wires. The memory controller decodes this binary pattern to select the exact memory cell. This fundamental binary addressing is why memory capacities are always powers of two.

Address Bus Width and Maximum Addressable Memory

The formula is simple: with n address lines, you can address 2^n unique memory locations. I've seen this principle play out across every generation of processors:

  • 8-bit CPU (6502, Z80): 16 address lines = 2^16 = 65,536 bytes = 64 KB
  • 16-bit CPU (8086): 20 address lines = 2^20 = 1,048,576 bytes = 1 MB
  • 32-bit CPU (i386, ARMv7): 32 address lines = 2^32 = 4,294,967,296 bytes = 4 GB
  • 64-bit CPU (x86-64, ARMv8): theoretically 2^64 = 16 EB, practically 48 bits = 256 TB

The 4 GB limit of 32-bit systems wasn't a marketing decision — it's a mathematical consequence of having only 32 binary address lines. I've debugged numerous "out of memory" issues on 32-bit systems that were simply hitting this hard binary ceiling.

Why 32-bit Systems Have a 4 GB Limit

The 4 GB ceiling is pure binary arithmetic. With 32 address bits, the CPU can generate addresses from 0000_0000_0000_0000_0000_0000_0000_0000 (address 0) to 1111_1111_1111_1111_1111_1111_1111_1111 (address 4,294,967,295). If each address refers to one byte, that's exactly 4,294,967,296 bytes = 4 GiB.

I remember working with 32-bit Windows XP systems where users were frustrated that their 4 GB of RAM only showed 3.2-3.5 GB usable. The "missing" RAM wasn't actually missing — the address space was shared with hardware devices (PCIe slots, graphics card memory, BIOS ROM). Each of those devices occupies a range of binary addresses. The graphics card's 512 MB of VRAM, for instance, maps into the address space between 1100_0000_0000_0000_0000_0000_0000_0000 and 1111_1111_1111_1111_1111_1111_1111_1111, consuming addresses that would otherwise be available for system RAM.

64-bit Addressing: The Theoretical Limit

In theory, 64 address bits give you 2^64 = 18,446,744,073,709,551,616 bytes = 16 exabytes (EiB). That's enough to address every byte in 16 billion 1 GB files simultaneously. In practice, current processors use fewer bits. I've worked with AMD64 and ARMv8 CPUs that implement 48-bit virtual addresses (2^48 = 256 TiB) and 52-bit physical addresses.

Why not use all 64 bits? Adding more address lines requires more pins on the CPU package, more traces on the motherboard, and larger page table data structures. The trade-off is between addressable capacity and cost. Even 256 TiB of RAM is far beyond what any current server configuration could physically accommodate. When I'm configuring server memory maps for virtualization hosts, the 48-bit limit is rarely a practical constraint.

Address Alignment and Binary Boundaries

Address alignment is a concept that every performance-conscious programmer needs to understand. A memory access is "aligned" when the address is a multiple of the data size. For example, a 4-byte integer is aligned when its address is a multiple of 4 — meaning the lowest 2 bits of the binary address are 0 (..._xxxx_xx00). An 8-byte (64-bit) double needs the lowest 3 bits to be 0 (..._xxxx_x000).

I've seen dramatic performance differences from misaligned access. On an ARM Cortex-A processor, a misaligned 4-byte load can take 6-8 cycles instead of 1-2 cycles because the memory controller must perform two separate bus transactions and shift the results. On x86, the penalty is smaller but still significant in tight loops. The binary pattern of the address determines alignment: an address ending in 000 binary is 8-byte aligned, 100 is only 4-byte aligned, 100 or 000 is 4-byte, and so on.

Array Indexing and Address Computation

When you access arr[i] in C or C++, the compiler calculates the address as base_address + (i * element_size). This is pure binary arithmetic. For an array of 4-byte integers starting at address 0x1000, arr[5] lives at 0x1000 + (5 * 4) = 0x1014. In binary that's 1_0000_0000_0000 + 1_0100 = 1_0000_0001_0100.

I've optimized many tight loops by leveraging this binary structure. When element_size is a power of two (4, 8, 16 bytes), the multiplication becomes a simple left shift in binary — the compiler replaces i * 8 with i << 3. This is why struct padding and array allocation often round sizes up to the nearest power of two. The binary address arithmetic is simpler and faster at the hardware level.

Page Tables: Virtual to Physical Address Translation

Modern operating systems use virtual memory, where each process sees a virtual address space that's mapped to physical RAM through page tables. Each page table entry is a binary structure containing the physical page frame number plus permission bits. On x86-64, the translation walks a 4-level page table hierarchy:

  • The virtual address's bits 47:39 select a PML4 entry
  • Bits 38:30 select a PDP entry
  • Bits 29:21 select a PD entry
  • Bits 20:12 select a PT entry
  • Bits 11:0 are the byte offset within the 4 KB page

Each of these bit ranges slices the 48-bit virtual address into binary fields. When I'm debugging kernel crash dumps, I mentally split addresses into these bit groups to navigate the page table hierarchy without a reference — it's just binary bit manipulation at every level.

Key Formulas

Addressable memory = 2^(address bus width) bytes · 32-bit max = 4 GiB · 48-bit (current 64-bit) = 256 TiB · Theoretical 64-bit = 16 EiB · Alignment check: address % N == 0 (N = data size)

Try It Yourself

Open the Binary Code Decoder in a new tab and enter some binary patterns to see the results instantly. All conversions happen in your browser — no data is sent to any server.