OnlineCBT Logo OnlineCBT
C Tutorial
C · LESSON 18

C Preprocessor Directives & Header Files

By Ratan Updated: 15 Oct 2026

Understand preprocessor macros (#define, #ifdef), conditional compilation, and custom header (.h) files.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive

Separate declarations from implementation

The preprocessor runs before the compiler analyzes C expressions. Directives begin with # and control inclusion, macro expansion and conditional compilation. Headers normally publish declarations; source files supply function definitions.

A small two-file module

Create a header named arithmetic.h:

#ifndef ONLINECBT_ARITHMETIC_H
#define ONLINECBT_ARITHMETIC_H
int add(int a, int b);
#endif

Create arithmetic.c:

#include "arithmetic.h"
int add(int a, int b) {
    return a + b;
}

Create main.c:

#include 
#include "arithmetic.h"
int main(void) {
    printf("sum=%d\n", add(4, 5));
    return 0;
}

Build both source files together: gcc -std=c17 -Wall -Wextra -pedantic main.c arithmetic.c -o demo. Expected output: sum=9. Linking only main.c leaves the definition of add missing.

Why include guards exist

The #ifndef/#define/#endif pattern prevents a header's declarations from being processed repeatedly within one translation unit. Choose a unique guard name. Avoid names starting with reserved underscore patterns. A header is not normally a place for ordinary externally linked function definitions or initialized global objects, which can cause multiple-definition errors when included in several source files.

Macro expressions and side effects

#define SQUARE(x) ((x) * (x))

Parentheses make SQUARE(2 + 3) expand with the intended grouping. They do not fix repeated evaluation: SQUARE(i++) expands to unsequenced modifications and is invalid. Prefer a typed function when evaluating a value once is important.

Conditional compilation

#ifdef DEBUG
    fputs("debug build\n", stderr);
#endif

This fragment needs stdio.h. Compile with an appropriate definition such as -DDEBUG to include it. A preprocessor condition is resolved during translation, whereas an ordinary if makes a decision in the running program.

Useful inspection commands

With GCC, gcc -E main.c displays preprocessed output; gcc -c arithmetic.c creates an object file without linking. Keep generated output separate from your hand-written source. Include the header in the corresponding implementation file so declaration/definition mismatches can be diagnosed.

Exercises

  1. Add a subtract function to the module, updating both the header and source.
  2. Include arithmetic.h twice and confirm the include guard prevents repeated processing problems.
  3. Replace SQUARE with int square(int x) and call it after a separate increment statement.
  4. Explain why a declaration alone cannot provide an implementation to the linker.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
पता संपर्क करें

+91 7877547686

ई-मेल

onlinecbtportal@gmail.com

हेल्पलाइन नंबर

+91 7877547686


डाउनलोड करने के लिए क्लिक करें
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat