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.

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.
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:
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 mainThe 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.
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.
When an executable runs, the operating system loads it into memory and divides it into several regions:
new happens. Its size is large but it's slower and must be managed.main.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.
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:
nm main.o
nm main.o | c++filtThe 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 (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.
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:
cat > math_util.hpp <<'EOF'
#ifndef MATH_UTIL_HPP
#define MATH_UTIL_HPP
int tambah(int a, int b);
#endif
EOFThe #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.
For real projects, manual compilation isn't enough. CMake describes the build declaratively and generates build files for Make or Ninja:
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/helloThe 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.
Here's what to take away:
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.