Why does C still exist?
Most languages protect you from yourself. They manage memory for you, check array bounds, prevent you from reading uninitialized variables. C does none of that. It gives you direct access to memory, no abstractions between you and the hardware.
That sounds terrifying. It is, until you understand it. Then it becomes a superpower. The Linux kernel is C. SQLite is C. The Python interpreter is C. When you need something to run fast, run small, or run forever, C is still the language you reach for.
A C program runs on bare metal
In Python, when you write x = [1, 2, 3], the runtime allocates a list object,
tracks its reference count, and will free it for you. In C, you are the runtime.
You decide where memory lives, how long it lives, and what happens when you're done with it.
This means more responsibility, but also more precision. A C program running on a 10-year-old embedded chip has no runtime overhead. It does exactly, and only, what you wrote.
The compilation pipeline
When you write C and run gcc hello.c -o hello, you think one thing happens.
Four things actually happen.
Each stage transforms the source into a lower-level representation.
You don't need to run them separately โ gcc hello.c -o hello does all four.
But understanding that they exist explains a lot of errors you'll see.
An "undefined reference" error happens at stage 4: the linker couldn't find a function you called.
gcc -O2 -S hello.c -o hello.s writes the generated assembly to a file.
You don't need to understand every line โ just knowing it exists demystifies what "compiling" means.
Your first C program, explained
The #include <stdio.h> line is a preprocessor directive โ it copies the
contents of stdio.h into your file before compilation. That header declares
printf so the compiler knows what it expects as arguments and return type.
main() is special: the OS calls it to start your program.
The return value is the exit code. Zero means success.
Non-zero means failure. The shell can check this with echo $?.
gcc -Wall -Wextra -o hello hello.c. Treat warnings as errors.
What comes next
The rest of this track is about what's happening beneath the surface. Variables aren't just names โ they're addresses. Types aren't just categories โ they're byte layouts. Functions aren't just calls โ they're memory frames pushed and popped on a stack.
Once you see C the way the machine sees it, bugs stop being mysterious. They become predictable consequences of specific rules you now know.
C is not a high-level language with extra steps โ it is a thin wrapper around the machine itself.