Orientation and Prerequisites

A computer's memory is a very long row of numbered boxes.

Learning Objectives

Describe what *memory*, a *program* and *program execution* mean in precise terms.

Name the layers between your code and the hardware: application, runtime, operating system, firmware and hardware.

Use bits, bytes, words, addresses and address spaces correctly.

Convert between binary, decimal and hexadecimal.

Know how to use this course: examples, visualizers, quizzes, glossary and the learning path.

Prerequisites

Basic programming: variables, functions, if statements and loops in any language.

Plain-Language Explanation

A computer's memory is a very long row of numbered boxes. Each box holds a small number (on almost every modern machine, one byte — eight bits). The box number is its address.

A program is a file containing two kinds of things: instructions the processor can carry out ("add these two numbers", "jump back to step 4") and data those instructions work on (the text "Hello", the number 42).

Program execution is what happens when the operating system copies that file's contents into memory and points the processor at the first instruction. From then on the processor repeats one cycle billions of times per second: *fetch* the next instruction from memory, *decode* what it means, *execute* it — which usually means reading or writing more memory.

Everything in this course is a closer look at one part of that story.

Precise Technical Explanation

What is memory?

In this course *memory* means addressable storage the processor can read and write with load and store instructions — registers, caches and main memory (RAM). Disks and SSDs are *storage*: the processor reaches them through device drivers and the operating system, not by ordinary loads. The distinction matters because the cost differs by up to a million times (Module 1).

What is a program?

A program exists in several forms during its life:

main.c, app.py People, compilers, interpreters assembly, object file, bytecode Assemblers, linkers, virtual machines a.out (ELF), app.exe (PE) The operating system's loader a running instance with its own memory The CPU and the operating system

One executable can be run as many processes at once; each has its own memory.

What does "program execution" mean?

Execution is the sequence: load (the OS maps the executable into a fresh address space), start (runtime start-up code prepares the stack, globals and arguments), run (the CPU fetches and executes instructions, the program calls the OS for I/O), and exit (the process returns a status and the OS reclaims every resource).

Hardware, firmware, operating system, runtime and application

Hardware executes instructions and stores bits.

Firmware is software stored in non-volatile memory on the board (UEFI, a microcontroller's boot ROM); it initialises hardware and starts the next stage.

Operating system (kernel) shares the hardware safely between programs: it creates processes, gives each a virtual address space, schedules them, and handles system calls.

Runtime is the code that runs *with* your program: the C start-up code and C library, or a virtual machine and garbage collector for Java, C#, JavaScript and Python.

Application is the code you wrote.

On a bare-metal microcontroller there may be no operating system: firmware jumps straight into your program (Module 16).

Bits, bytes, words, addresses and address spaces A bit is 0 or 1. A byte is the smallest *addressable* unit — 8 bits on every mainstream platform (C calls the count CHAR_BIT).

A word is the natural data size of a processor (its register width): 32 bits on a 32-bit CPU, 64 bits on x86-64 and AArch64. Unfortunately vendors also use "word" for fixed sizes — on x86, WORD means 16 bits for historical reasons. Always check the context.

An address is the number of a byte. An address space is the set of all addresses a program can form: 2³² addresses (4 GiB) for 32-bit pointers, and on x86-64 Linux a 47-bit user range today (128 TiB), even though pointers are stored in 64 bits.

Binary, decimal and hexadecimal Memory contents are binary, but long binary strings are unreadable. Hexadecimal (base 16, digits 0–9 a–f) is used because each hex digit is exactly four bits, so one byte is always two hex digits.

To convert hex to decimal, multiply each digit by a power of 16: 0x2A = 2×16 + 10 = 42. To convert decimal to hex, divide by 16 repeatedly and read the remainders backwards: 300 = 18×16 + 12 and 18 = 1×16 + 2, so 300 = 0x12C.

How to use the course Read the plain-language explanation first, then the precise one. Run every example yourself (the toolchains are listed in the Course Overview), use the visualizer, try the three exercises, and only then take the quiz. The glossary at the end defines every acronym.

flowchart TB
  A[Application code — your functions] --> R[Language runtime — C library, JVM, CLR, V8, CPython]
  R --> O[Operating system kernel — processes, virtual memory, files, scheduling]
  O --> F[Firmware — UEFI/BIOS, boot ROM, microcode]
  F --> H[Hardware — CPU, caches, RAM, devices]

Why It Matters in Real Systems

Every crash report, performance profile and security advisory is written in this vocabulary: "segmentation fault at address 0x0", "L1 cache miss", "heap-buffer-overflow", "page fault". You cannot read them — let alone fix the problem — without a clear model of memory and execution.

Key Terms

A binary digit, 0 or 1 Smallest addressable unit; 8 bits on mainstream platforms

A processor's natural register width (context-dependent) The number identifying one byte of an address space All addresses a program can use

A running instance of a program, with its own address space Code that runs alongside the program: C library, VM, garbage collector

Software stored in non-volatile memory that initialises the hardware

Memory Layout and Execution Flow

flowchart LR
  S[Source file] --> B[Build tools] --> E[Executable file] --> L[OS loader] --> P[Process in memory] --> C[CPU fetch-decode-execute]

Syntax

No dedicated syntax; this is an orientation module. The C notation 0x2A (hexadecimal literal) and 0b101010 (binary literal — standard in C23 and C++14, a GCC extension in earlier C) appear throughout the course.

Complete Runnable Example

A first program that prints the same number in three bases and shows the sizes this platform uses. Compiler: GCC 11.2, x86-64 Linux.

#include <stdio.h>
#include <limits.h>

int main(void)
{
    unsigned int n = 300;

    printf("decimal %u = hex 0x%X = octal 0%o\n", n, n, n);
    printf("bits per byte (CHAR_BIT): %d\n", CHAR_BIT);
    printf("sizeof(char)=%zu sizeof(int)=%zu sizeof(long)=%zu sizeof(void *)=%zu\n",
           sizeof(char), sizeof(int), sizeof(long), sizeof(void *));
    return 0;
}

Line-by-Line Explanation

#include <limits.h> provides CHAR_BIT, the number of bits in a byte for this implementation.

%u, %X and %o print the same unsigned value in decimal, upper-case hex and octal.

sizeof yields the size of a type in bytes as a size_t, printed with %zu.

sizeof(char) is 1 by definition in C; every other size is implementation-defined.

Expected Output

On 64-bit Windows sizeof(long) is 4, not 8 — Windows uses the LLP64 data model, Linux and macOS use LP64. This is the first of many platform differences the course points out.

decimal 300 = hex 0x12C = octal 0454
bits per byte (CHAR_BIT): 8
sizeof(char)=1 sizeof(int)=4 sizeof(long)=8 sizeof(void *)=8

Step-by-Step Execution Trace

The loader maps the executable and starts the C runtime, which calls main.

n receives 300 (0x12C).

printf formats 300 three ways and writes the text to standard output through a write system call.

Each sizeof was already computed by the compiler; the program only prints constants.

main returns 0; the runtime flushes output and the process exits with status 0.

Interactive Visualization

Type a value into the byte viewer and watch it appear in decimal, hex and binary, one byte at a time.

Common Mistakes and Failure Modes

Assuming int is always 4 bytes or long is always 8. Use <stdint.h> types (int32_t, uint64_t) when the width matters.

Reading 0x10 as ten. It is sixteen.

Confusing *storage* (disk) with *memory* (RAM). A file on disk is not "in memory" until something reads or maps it.

Corrected / Safe Pattern

#include <stdint.h>
uint32_t checksum = 0;        /* exactly 32 bits on every platform that provides it */
size_t   count    = 0;        /* the right type for sizes and indexes */

Debugging and Diagnostic Techniques

Print values in hex (%x, %#x) whenever you inspect addresses or bit patterns; debuggers do the same. printf("%zu", sizeof x) answers "how big is this, here?" faster than any document.

Performance Implications

None yet — but the numbers in this module return in every performance discussion: word size decides how much data one instruction moves, and address width decides how much memory a process can use.

Security and Safety Implications

Wrong assumptions about sizes are a classic source of bugs: copying 8 bytes into a 4-byte field, or truncating a 64-bit length to 32 bits. Module 9 covers these in depth.

Platform and Language Caveats

Byte = 8 bits on all mainstream CPUs; some DSPs have 16- or 32-bit "bytes".

Data models: LP64 (Linux, macOS: long and pointers 64-bit) versus LLP64 (Windows: long 32-bit, pointers 64-bit).

Managed languages (Java, C#, Python, JavaScript) hide addresses entirely; their sizes are defined by the language, not the machine.

Real-World Application

Hex is the language of memory dumps, network packets, register maps and file formats. Every embedded datasheet lists registers by hex address; every crash log prints addresses in hex.

Best Practices Checklist

[ ] Use fixed-width integer types when the size matters.

[ ] Use size_t for sizes and indexes.

[ ] Write addresses and bit masks in hex.

[ ] State the platform whenever you state a size.

Exercises

E1 · Beginner. Convert 2024 to hex and 0xBEEF to decimal by hand.

Answer: 2024 = 7×256 + 14×16 + 8 = 0x7E8. 0xBEEF = 11×4096 + 14×256 + 14×16 + 15 = 48879.

E2 · Intermediate. How many distinct addresses does a 20-bit address bus provide, and how much byte-addressable memory is that?

Answer: 2²⁰ = 1,048,576 addresses = 1 MiB (the original 8086).

E3 · Advanced challenge. Modify the example to print sizeof(size_t), sizeof(long long) and sizeof(long double). Explain why long double can be 16 bytes while holding only 80 bits of data on x86-64.

Answer: x86 extended precision uses 80 bits; the System V ABI pads it to 16 bytes so arrays of long double stay 16-byte aligned. Size includes padding, not just the value bits.

Quiz

? How many bits does one hexadecimal digit represent?
- 2 :: Two bits give only four values (0–3).
+ 4 :: Four bits give 16 values, exactly the digits 0–F.
- 8 :: Eight bits are a byte — two hex digits.
- 16 :: Sixteen is the base, not the bit count.

? Which statement about a "word" is correct?
- It is always 16 bits. :: That is only x86 assembler terminology (WORD).
+ It usually means the processor's natural register width, but vendors use the term differently. :: Always check the documentation's definition.
- It is always 32 bits. :: 64-bit processors have 64-bit registers.
- It is the same as a byte. :: A byte is the smallest addressable unit; a word is usually several bytes.

? Select all that are part of a running program's environment beyond your own code. (select all that apply)
+ The C library or language runtime :: It provides start-up code, I/O and memory allocation.
+ The operating system kernel :: It creates the process and handles system calls.
- The source file on disk :: The process runs the loaded executable; the source is not needed.
+ Firmware that initialised the hardware :: It ran first and still provides services on some systems.

Summary

Memory is a numbered array of bytes; a program is instructions plus data; execution is the loader placing the program in a process and the CPU running its fetch-decode-execute cycle. Hexadecimal is the notation of memory because one hex digit is four bits. Sizes such as int and long are platform choices, not universal facts.

References and Further Reading

Bryant & O'Hallaron, *Computer Systems: A Programmer's Perspective*, chapters 1–2.

ISO/IEC 9899:2018 (C17), §5.2.4.2.1 "Sizes of integer types".

Patterson & Hennessy, *Computer Organization and Design*, chapter 1.