Introduction to C · Lesson 3 of 35
How a C Program Is Compiled and Run
Typing gcc hello.c -o hello looks like one step, but four tools run behind it. Understanding them explains confusing errors ("undefined reference" vs "undeclared"), how header files work, and why C programs are fast. It's also a favourite viva and interview question.
In this lesson
- The four stages: preprocess, compile, assemble, link
- Seeing each stage with gcc flags
- Compile errors vs link errors vs runtime errors
- How a running program is laid out in memory
The four stages
From hello.c to a running program
- Preprocessorhandles #include and #define → expanded source (hello.i)
- Compilerchecks syntax and types, translates C to assembly (hello.s)
- Assemblerturns assembly into machine code → object file (hello.o)
- Linkerjoins object files with libraries (printf lives in libc) → executable
- Loaderthe OS loads the executable into memory and calls main
You can stop gcc after any stage to look at the result:
gcc -E hello.c -o hello.i # preprocess only: see what #include pasted in
gcc -S hello.c -o hello.s # compile to assembly
gcc -c hello.c -o hello.o # compile + assemble: object file, not yet runnable
gcc hello.o -o hello # link into an executable
The preprocessor at work
#include <stdio.h>
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
int main(void) {
double r = 2.0;
printf("Area = %.2f\n", PI * SQUARE(r)); // becomes 3.14159 * ((r) * (r))
return 0;
}
Area = 12.57
The preprocessor does plain text substitution before the compiler sees the code: PI is replaced by 3.14159 everywhere. Chapter 12 covers macros and their traps in detail.
Three kinds of errors
| Error type | Found by | Example |
|---|---|---|
| Compile-time (syntax/type) | compiler | missing semicolon, undeclared variable, wrong argument type |
| Link-time | linker | undefined reference to 'calculate' – declared but never defined, or a library not linked (-lm) |
| Runtime | running the program | division by zero, reading outside an array, a segmentation fault |
| Logical | you, by testing | the program runs but gives the wrong answer |
#include <stdio.h>
int square(int n); // declaration: promises the function exists
int main(void) {
printf("%d\n", square(7));
return 0;
}
int square(int n) { // definition: the actual code (remove it → linker error)
return n * n;
}
49
A program in memory
When the loader starts your program, it gives it memory divided into regions. You'll meet each of them in later chapters:
Memory layout of a running C program (high addresses at the top)
- Stacklocal variables and function calls; grows and shrinks automatically
- ↓ free space ↑the stack and heap grow towards each other
- Heapmemory you allocate with malloc and release with free
- BSSglobal and static variables without an initial value (set to 0)
- Datainitialised global and static variables
- Text (code)the machine instructions; usually read-only
#include <stdio.h>
#include <stdlib.h>
int counter = 10; // data segment
int unset; // BSS: starts at 0
int main(void) {
int local = 5; // stack
int *dynamic = malloc(sizeof *dynamic); // heap
if (dynamic == NULL) return 1;
*dynamic = 42;
printf("counter=%d unset=%d local=%d dynamic=%d\n", counter, unset, local, *dynamic);
free(dynamic);
return 0;
}
counter=10 unset=0 local=5 dynamic=42
Practice
Quick check
What are the four stages of compilation?
Preprocessing, compilation, assembly and linking.
"undefined reference to sqrt" – which stage, and the fix?
The linker; link the maths library with -lm.
Which gcc flag stops after creating an object file?
-c.
Where do local variables live?
On the stack.
Summary
- gcc runs the preprocessor, compiler, assembler and linker in turn.
- Compile errors come from syntax/types, link errors from missing definitions or libraries.
- A running program has text, data, BSS, heap and stack regions.
Interview practice: C language basics interview questions.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.