$ overview
overview/0x0F·Working With The System

Multi-File Programs

Header files, the compile-then-link model, and keeping code organized.

Real C programs are rarely one file. Splitting code across multiple .c files keeps related logic together and lets each file be compiled independently — only the files that changed need to be recompiled, which matters once a project grows large.

Header files declare, source files define

A header (.h) lists what a module offers, without the implementation. A source file (.c) provides the actual code:

math_utils.h
1#ifndef MATH_UTILS_H
2#define MATH_UTILS_H
3 
4int square(int n);
5int cube(int n);
6 
7#endif
math_utils.c
1#include "math_utils.h"
2 
3int square(int n) {
4 return n * n;
5}
6 
7int cube(int n) {
8 return n * n * n;
9}
main.c
1#include <stdio.h>
2#include "math_utils.h"
3 
4int main(void) {
5 printf("%d\n", square(4));
6 printf("%d\n", cube(3));
7 return 0;
8}

Compiling multiple files

terminal
1gcc main.c math_utils.c -o program
2./program

Each .c file is compiled separately into an object file, then the linker (0x00) combines them into one executable. main.c only needs the header to know square and cube exist — it doesn't need to see how they're implemented.

note: Why the split matters as projects grow
With larger projects, you compile each changed file into an object file (gcc -c file.c) and link the object files together, so an edit to one file doesn't require recompiling everything. Build tools like make automate exactly this.

What goes in a header

  • Function prototypes (declarations, not definitions).
  • struct and typedef definitions shared across files.
  • #define constants meant to be shared.
error: Don't put function bodies in headers
If a header with a full function definition is included by two different .c files, the linker sees that function defined twice and refuses to build — a "multiple definition" error. Headers declare; exactly one source file defines.