Learn C Language - Core Concepts & Main Architecture
Episode 2 of 24

Learn C Language - Core Concepts & Main Architecture

This episode digs into what happens behind the scenes: the four-stage compilation process, the C memory model that divides the stack, heap, static data, and text segments, and the ABI and calling convention. You will also see the structure of a C program and the toolchain flow.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

A C program does not become an executable directly. An entire pipeline works behind the scenes, from preprocessing to linking. Understanding this pipeline lets you diagnose compiler errors, read linker messages, and optimize binary size.

Episode 2 dissects the internal architecture of the C language: the four stages of compilation, the memory model that divides the address space into different segments, the ABI and calling convention that connect functions, and the program structure and toolchain that put it all together.

After this episode, you will no longer see C code as plain text, but as a blueprint that runs through a precise transformation engine.

The Four-Stage Compilation Process

Preprocessing

The first stage reads directives that begin with the # sign. The preprocessor replaces #include with the header contents, expands #define macros, and filters out #ifdef sections. The result is a file with all includes already expanded. Run this stage yourself with:

Stop the pipeline at preprocessing
gcc -E program.c -o program.i
wc -l program.i

The command gcc -E program.c -o program.i produces a temporary file much longer than the original source, because it contains the entire contents of the included headers.

Compilation and Assembly

The second stage translates C into architecture-specific assembly, then the third stage translates the assembly into an object file of machine code. Object files cannot be run yet because references to functions from other files are still unresolved:

View assembly and object file
gcc -S program.c
gcc -c program.c -o program.o
file program.o

The -S flag produces a .s file containing assembly, while -c produces a .o object file. To see the symbols defined inside an object file, use nm:

List object file symbols
nm program.o

The output of nm program.o shows symbols such as main and library functions that are still undefined.

Linking

The final stage is linking: the linker combines all object files, resolves references between functions, and attaches runtime libraries such as libc. The result is an executable:

Full linking
gcc program.o -o program
readelf -h program

readelf -h program displays the ELF header, including the architecture, file type, and entry point. Of the four stages above, only the first two are usually visible to programmers; errors that appear at the linking stage typically read undefined reference.

The C Memory Model

The Four Main Segments

When an executable is loaded, the operating system divides the process memory into several segments:

  • Text segment: contains machine code, read-only.
  • Static data: contains global and static variables, divided into initialized data and zeroed BSS.
  • Stack: holds local variables and function frames, grows downward, managed automatically.
  • Heap: memory dynamically allocated with malloc, managed manually by the programmer.

Global variables live for the whole program, local variables live only while their function is called, and heap data lives until free is called.

View program memory segments
size program

The command size program shows the text, data, and bss segment sizes at a glance. This is a quick way to inspect a program's memory footprint.

ABI and Calling Convention

Contract Between Components

The ABI (Application Binary Interface) is a binary-level contract: data type sizes, struct layout, and how functions are called. The calling convention is the part of the ABI that determines how arguments are passed to functions — through which registers, and how values are returned.

On x86_64 Linux, the System V convention places the first argument in the rdi register, the second in rsi, and so on. Programs that follow the same ABI can interoperate even if written in different files. This is what allows the printf function from libc to be called from your code.

Practical Impact for Programmers

Understanding the ABI helps you read errors like undefined reference, understand why structs need alignment (episode 17), and why binary libraries must be built with a compatible ABI. ABI mismatch is a classic cause of crashes when linking libraries compiled with different compilers.

Program Structure and Toolchain

Main Components of a C Program

A healthy C project consists of several components: header files that declare the interface, source files that provide the implementation, and a single main function as the entry point. Preprocessor directives like #include and #define are in charge, while the linker brings everything together with static or shared libraries.

Toolchain Flow and Debugging

The basic toolchain works in one flow: edit in your editor, compile with gcc or clang, link, then run. If a crash occurs, a debugger like gdb reads the core file and stack to find the cause. Episode 11 will cover debugging in depth, but the flow always starts with understanding the pipeline above.

Tip

A good habit: compile with gcc -Wall -Wextra -g. The first two flags turn on warnings, and -g stores the debug information needed by gdb and valgrind.

Closing

Key takeaways:

  • C compiles through four stages: preprocessing, compilation, assembly, and linking.
  • -E, -S, -c, and full linking separate each pipeline stage.
  • The C memory model has text, static data, stack, and heap, each with its own lifetime rules.
  • The ABI and calling convention are the binary contract connecting separate components.
  • undefined reference errors appear at the linking stage, not compilation.
  • Always compile with -Wall, -Wextra, and -g to keep the pipeline visible.

In the next episode 3 we will discuss C's basic syntax and program structure — variable declarations and basic data types, the main function, statements, code blocks, comments, and putting together and running a simple program.