How a C++ Program is Compiled and Run
You already ran a program
In the last lesson you saw your first C++ program and pressed Run. Something appeared on the screen. But what actually happened between those two moments?
It turns out “pressing Run” is not one step. It’s several, each handled by a different tool. Understanding those steps will make error messages less mysterious and give you a clearer picture of what C++ actually is.
The big picture
Your code is initially written in a text file with a .cpp extension. It goes through three stages before it becomes a running program.
C++ compilation pipeline
Let’s walk through each one.
Stage 1: The preprocessor
The preprocessor is the first tool that touches your code. Its job is to look for lines that start with # and handle them before anything else happens.
You’ve already seen one:
#include <iostream>When the preprocessor sees this line, it finds the file named iostream and copies its entire contents into your code right at that spot. By the time it’s done, your file is much longer than you wrote. All the definitions needed to make std::cout work are now present.
Stage 2: The compiler
After the preprocessor finishes, the compiler takes over.
The compiler reads your code and translates it into machine code: the raw binary instructions your CPU actually understands. Your source code is human-readable text, but the machine code isn’t.
Stage 3: The linker
The compiler alone doesn’t produce a runnable program. It produces an intermediate .o file (called an object file) that still has some gaps. The linker’s job is to fill those gaps and produce the final result.
For example, when you write std::cout, the actual code that makes output work is not something you wrote yourself. It lives in the standard library that ships with C++. The linker finds that code and connects it to your program.
For the small programs you’re writing now, this all happens invisibly. But knowing that the linker exists helps explain some obscure error messages. For example an error like “undefined reference” or “unresolved symbol” means a piece of code your program needs couldn’t be located.
The result
What comes out the other end is an executable: a file of machine code that your computer can run directly. On this platform, pressing “Run” handles all three stages automatically.
Two kinds of errors
This is one of the most useful things to understand early, because it changes how you read error messages.
1. Compile-time errors
Compile-time errors are caught by the compiler before your program ever runs. For example, a missing semicolon, a misspelled name, or using something you haven’t defined yet all produce compile-time errors.
The compiler typically gives an error message with a line number to help identify the source of the problem.
We took the program from the last lesson and removed the semicolon after return 0 on line 5:
If you press “Run”, you’ll see the program didn’t run at all. The compiler caught the problem first and told you exactly where to look.
2. Runtime errors
Runtime errors happen after compilation succeeded and the program is actually running. The code was valid enough for the compiler to accept, but something went wrong during execution.
For example, consider a program that divides a number by a value entered by the user. The code will compile fine, but if the user enters zero, the program will crash because dividing by zero is undefined. This kind of error is not caught at compile time because the compiler has no way to know what the user will type.