Learn C++ - Core Concepts & Main Architecture
Series/Learn C++/Episode 2
Episode 2 of 24

Learn C++ - Core Concepts & Main Architecture

This episode dissects how C++ works behind the scenes: the compilation process from preprocessing to linking, the stack and heap memory model, ABI and name mangling, program structure with header and source files, and build workflows with CMake.

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

Introduction

C++ code doesn't just run. There's a chain of processes that turns the text you write into executable machine instructions. Understanding this process lets you read linker errors, fix symbol problems, and optimize builds.

Episode 2 covers the architecture behind C++: the four-stage compilation pipeline, the program memory model, ABI and name mangling, project structure with header and source files, and how CMake ties it all together. This is the technical foundation used in every following episode.

The Compilation Process from Source to Binary

The Four Stages of Compilation

Modern compilers turn main.cpp into an executable in four stages. The preprocessing stage processes directives like #include and #define. The compilation stage translates the processed code into assembly. The assembly stage turns assembly into an object file with machine instructions. The final stage, linking, combines all object files and libraries into an executable.

You can see each stage separately with compiler flags:

See the four compilation stages
g++ -E main.cpp -o main.i
g++ -S main.i -o main.s
g++ -c main.s -o main.o
g++ main.o -o main

The command g++ -E main.cpp -o main.i only runs preprocessing and outputs the main.i file. -S produces assembly main.s, -c produces the object file main.o, and without those flags a full link is performed.

Why This Matters

Most confusing errors come from the last stage: linking. When you see an undefined reference message, it means the compiler couldn't find the definition of a called function — the cause could be a missing header or a library that wasn't linked. In episode 5, you'll build multi-file projects and deal with this problem directly.

The C++ Program Memory Model

Four Memory Regions

When an executable runs, the operating system loads it into memory and divides it into several regions:

  • Stack: stores local variables and function call addresses. Grows downward, has limited size, and is fast.
  • Heap: where dynamic allocation with new happens. Its size is large but it's slower and must be managed.
  • Static/Global: data that lives for the whole program, initialized before main.
  • Code segment: read-only machine instructions.

Every new allocation takes space from the heap, while local variables automatically go on the stack. This difference determines how resources are managed, and will be discussed in depth in episode 7.

ABI, Name Mangling, and Linking

Name Mangling

C++ allows multiple functions with the same name as long as their parameters differ — this is called overloading. To distinguish them at the object file level, the compiler assigns unique internal names through name mangling. A function tambah(int, int) becomes a mangled name like _Z5tambedd.

You can inspect and reverse name mangling with nm and c++filt:

Inspect object file symbols
nm main.o
nm main.o | c++filt

The command nm main.o | c++filt lists the symbols then demangles their names so they read as tambah(int, int). These tools are a big help when investigating linker errors.

ABI and Compatibility

ABI (Application Binary Interface) is the binary contract between the compiler, libraries, and executable: how functions are called, how structs are laid out in memory, and how exceptions are propagated. Libraries compiled with a different ABI can't be safely linked. That's why C++ libraries often ship binary versions for specific compilers and standards.

The Structure of a C++ Program

Headers, Sources, and Namespaces

A C++ project is split into header files (.hpp) containing declarations and source files (.cpp) containing definitions. Namespaces separate symbols so they don't collide — std is the main namespace of the standard library. The #include <iostream> directive inserts the contents of the iostream header into your file.

Include guards prevent a header file from being included twice in a single translation unit:

Header with an include guard
cat > math_util.hpp <<'EOF'
#ifndef MATH_UTIL_HPP
#define MATH_UTIL_HPP
 
int tambah(int a, int b);
 
#endif
EOF

The #ifndef MATH_UTIL_HPP pattern ensures declarations are only processed once. Starting with C++20, the modules feature offers a cleaner alternative, and will be covered in episode 16.

Build Workflows with CMake

Your First CMakeLists.txt

For real projects, manual compilation isn't enough. CMake describes the build declaratively and generates build files for Make or Ninja:

Minimal CMakeLists
cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.20)
project(hello LANGUAGES CXX)
 
add_executable(hello main.cpp)
set(CMAKE_CXX_STANDARD 20)
EOF
cmake -S . -B build
cmake --build build
./build/hello

The flow cmake -S . -B build configures the project into the build directory, then cmake --build build runs the default backend (Make or Ninja) to compile. After the build, the hello executable is ready to run. This pattern will be used in almost every following episode.

Info

Never write -std=c++20 inside a CMakeLists; use set(CMAKE_CXX_STANDARD 20) so it stays consistent across all compilers and generators.

Conclusion

Here's what to take away:

  • Compilation runs in four stages: preprocessing, compilation, assembly, linking.
  • Stack for local variables, heap for dynamic allocation, static for global data.
  • Name mangling distinguishes overloaded functions at the binary level.
  • The ABI determines binary compatibility between compilers and libraries.
  • Headers contain declarations, sources contain definitions, namespaces separate symbols.
  • CMake manages builds declaratively and produces the executable.

In the next episode, episode 3, we'll discuss basic syntax and program structure — variable declarations, constants, and fundamental types, statements and code blocks, functions with scope and return values, and your first interactive program with std::cin and std::cout. It's time to actually start writing C++ code.