Preprocessor & Headers
Code organization and compilation
Introduction
In this lesson, you'll learn about preprocessor & headers in C. Coming from JavaScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In JavaScript, you're familiar with code organization and compilation.
C has its own approach to code organization and compilation, which we'll explore step by step.
The C Way
Let's see how C handles this concept. Here's a typical example:
/* math.h — header file (declarations) */
#ifndef MATH_H /* include guard */
#define MATH_H
#define PI 3.14159
int add(int a, int b);
#endif /* MATH_H */
/* math.c — implementation */
#include "math.h"
int add(int a, int b) { return a + b; }
/* main.c — usage */
#include <stdio.h> /* angle brackets = system */
#include "math.h" /* quotes = local */
#define DEBUG 1
int main() {
#if DEBUG
printf("debug mode\n");
#endif
printf("%.5f\n", PI);
printf("%d\n", add(2, 3));
return 0;
}Comparing to JavaScript
Here's how you might have written similar code in JavaScript:
// math.js — module
export function add(a, b) { return a + b; }
export const PI = 3.14159;
// main.js
import { add, PI } from "./math.js";
// Constants
const DEBUG = process.env.NODE_ENV !== "production";
if (DEBUG) console.log("debug mode");You may be used to different syntax or behavior.
C uses .h header files for declarations; JS uses import/export
You may be used to different syntax or behavior.
C #define creates text-substitution macros; JS has no preprocessor
You may be used to different syntax or behavior.
#include guard (#ifndef) prevents double-inclusion; JS handles this automatically
You may be used to different syntax or behavior.
C compilation: preprocess → compile → link; JS has no separate compile step
Step-by-Step Breakdown
1. Header Files
C header files (.h) declare functions and types that other files can use. The .c file provides the actual implementation.
// math.js — export function add() {...}/* math.h */ int add(int a, int b); // declaration only
/* math.c */ int add(int a, int b) { return a+b; } // definition2. Include Guards
Without include guards, a header included twice causes duplicate declarations. #ifndef/#define/#endif prevents this.
#ifndef MY_HEADER_H
#define MY_HEADER_H
// ... declarations ...
#endif3. #define Macros
#define is pure text substitution — dangerous if misused. Prefer const and inline functions for type safety.
#define MAX(a,b) ((a)>(b)?(a):(b)) // macro — no types
// vs:
static inline int max(int a, int b) { return a > b ? a : b; } // saferCommon Mistakes
When coming from JavaScript, developers often make these mistakes:
- C uses .h header files for declarations; JS uses import/export
- C #define creates text-substitution macros; JS has no preprocessor
- #include guard (#ifndef) prevents double-inclusion; JS handles this automatically
Key Takeaways
- Header files (.h) declare; .c files define
- Include guards prevent double-inclusion
- #define for macros and conditional compilation
- System headers use < >; local headers use quotes