Visual walkthrough — Preprocessor directives — #define, #ifdef, #ifndef, #include guards
5.1.27 · D2· Coding › C Programming › Preprocessor directives — #define, #ifdef, #ifndef, #include
Step 1 — #include actually kya karta hai
KYA. Ek C program usually kai files mein split hota hai. Text ka ek piece (jaise ek struct definition) files ke beech share karne ke liye, tum use ek header file (.h file) mein rakhte ho aur jahan chahiye wahan #include "types.h" likhte ho.
YEH tool kyun, hand se copy-paste kyun nahi? Kyunki preprocessor — woh text-editing robot jo compiler se pehle chalta hai — tumhare liye pasting karta hai, automatically, har build mein. Tum text ek baar likhte ho; #include jahan bhi appear karta hai wahan ek fresh copy stamp kar deta hai. Koi bhi tool abhi C ko "samajhta" nahi; yeh pure find-and-glue hai.
TASVEER. Figure dekho. Left mein ek choti file types.h hai jisme ek struct hai. Blue arrow dikhata hai ki #include "types.h" kya ban jaata hai: preprocessor #include line delete karta hai aur file ka poora text uski jagah daal deta hai.

Term by term, transformation yeh hai:
Step 2 — Files doosri files include karti hain (diamond banta hai)
KYA. Headers, headers include karti hain. Maano a.h ko Point chahiye, toh a.h #include "types.h" likhti hai. Usi tarah b.h ko Point chahiye, toh b.h bhi #include "types.h" likhti hai. Ab tumhara main.c dono features chahta hai, toh woh dono include karta hai:
#include "a.h"
#include "b.h"PARWAH KYUN? Kyunki har #include ek independent paste hai. Preprocessor ko yaad nahi rehta ki woh a.h ke liye types.h already handle kar chuka hai — jab woh b.h tak pahuncha, toh woh types.h ko dobara paste karta hai.
TASVEER. Figure ek diamond hai: main.c upar, do paths (a.h aur b.h) bahar fanate hue, dono neeche usi same types.h ki taraf point karte hue. types.h par do arrows pahunchte hain — yeh warning sign hai: do routes, ek file, do pastes aane waali hain.

Step 3 — Double-paste hote dekho
KYA. main.c ko literally expand karte hain. Preprocessor upar se neeche kaam karta hai. Woh #include "a.h" dekhta hai, a.h ka text paste karta hai — aur us text ke andar #include "types.h" hai, jo woh bhi paste karta hai. Phir woh #include "b.h" tak pahunchta hai aur poora kaam dobara karta hai.
RAW EXPANSION KYUN DIKHAYEIN? Kyunki bug source mein invisible hai, lekin jab tum pasted result dekhte ho toh obvious hai. Final translation unit — poora expanded text jo compiler ko diya jaata hai — mein struct line do baar hai.
TASVEER. Figure resulting translation unit ko stack karke dikhata hai. Pehla pink block struct Point { int x, y; }; hai a.h path se. Doosra pink block bilkul same line hai b.h path se. Do identical blocks, ek file.

Step 4 — Compiler "redefinition" kyun chillata hai
KYA. Compiler ab translation unit padhta hai aur struct Point { int x, y; }; ko doosri baar milta hai. Same struct ko ek translation unit mein do baar define karna illegal C hai — compiler redefinition of 'struct Point' jaisi error ke saath ruk jaata hai.
DUPLICATION ILLEGAL KYUN HAI? Kyunki ek definition compiler ko ek type ki complete shape batati hai (uske members, uska size). Do definitions alag ho sakti hain; jab identical bhi hon, language ek unit mein doosri full definition forbid karti hai taaki meaning unambiguous rahe.
TASVEER. Figure compiler ko do blocks mein se padते hue dikhata hai: pehle block ko green check milta hai ("Point seekha ✓"); doosre ko pink cross milta hai aur ek speech bubble "Main Point pehle se jaanta hoon — yeh redefinition hai!"

Step 5 — Idea: ek "kya main yahan aa chuka hoon?" flag
KYA. Humein file ko notice karna hai: "doosri baar jab tum mujhe paste karo, kuch mat karo." Preprocessor apne aap yaad nahi rakh sakta — lekin woh ek cheez yaad rakh sakta hai: koi naam abhi defined hai ya nahi.
YEH tool kyun — #define as a flag? #define NAME (bina value ke) bas ek naam ko "defined" state mein switch kar deta hai. Isme koi memory nahi lagti, koi type nahi — yeh ek light switch hai jo preprocessor baad mein #ifdef / #ifndef se check kar sakta hai. "Kya yeh naam defined hai?" ka woh sawaal exactly wahi memory hai jo Step 2 mein nahi thi.
TASVEER. Figure TYPES_H labelled ek light switch dikhata hai. Left panel: OFF ("not defined"). Right panel: ON ("defined"). Neeche dono mein, preprocessor #ifndef TYPES_H poochta hai ("kya yeh not defined hai?") aur jawab YES → keep se NO → skip mein badal jaata hai.

Step 6 — Header ko guard mein wrap karo
KYA. Poori header body ko teen lines ke beech rakho: flag check karo, flag set karo, ...body..., band karo.
/* types.h */
#ifndef TYPES_H /* (1) kya flag OFF hai? */
#define TYPES_H /* (2) abhi ON karo */
struct Point { int x, y; }; /* (3) body */
#endif /* (4) check band karo */EXACTLY EES ORDER MEIN KYUN? Line (2) line (1) ke turant baad aani chahiye taaki flag pehle kisi bhi doosri paste ke hone se set ho jaaye. Jab ek baar header enter ho jaata hai, TYPES_H on hai — toh baad ka koi bhi paste switch pehle se on paata hai aur skip ho jaata hai.
TASVEER. Figure charon lines ko coloured tags ke saath annotate karta hai: yellow "(1) poochho", blue "(2) switch set karo", white "(3) real content", pink "(4) end". Ek arrow body se waapis upar loop karta hai guard dikhane ke liye.

Step 7 — Diamond ko dobara chalao, ab guarded
KYA. Step 3 ko guard ke saath re-run karo.
- Pehli paste (
a.hke zariye):TYPES_HOFF hai →#ifndeftrue hai → preprocessor use ON karta hai aurstructrakhta hai. ✔ body ek baar appear hoti hai. - Doosri paste (
b.hke zariye):TYPES_Hab ON hai →#ifndeffalse hai → preprocessor#endiftak sab kuch delete karta hai. ✘ body skip.
YEH FIX KYUN HAI. Struct ab translation unit mein exactly ek baar land karta hai, toh Step 4 ka compiler check pass ho jaata hai.
TASVEER. Figure Step 3 ka two-block stack repeat karta hai, lekin doosra block greyed-out aur crossed hai, caption ke saath "flag already ON → skipped." Sirf ek live pink block bachta hai.

Step 8 — Edge cases jo guard ko survive karne chahiye
KYA. Teen scenarios jo beginners ko trip karte hain:
- Do headers, same tag. Agar
a.haurb.hdono#ifndef HEADER_Huse karein, toh jo pehle paste hogi woh switch ON karti hai aur doosre ko completely block kar deti hai — tumhara doosra header silently gayab ho jaata hai. Fix: har tag unique rakho, e.g. filename se derive karo (A_H,B_H). - Ek file jo kabhi double-include nahi hoti. Guard yahan kuch nahi kosta —
#ifndefek baar true hai, kabhi false nahi. Yeh harmless insurance hai; phir bhi headers ko hamesha guard karo. #pragma onceinstead. Top par ek line same kaam karti hai file ki identity track karke, koi naam nahi. Yeh mistyped tag se clash nahi kar sakti — lekin yeh compiler-specific hai, jabki#ifndeftrio standard C har jagah hai.
ALAG STEPS KYUN? Kyunki "mere file par compile hua" case 1 ko completely hide karta hai; tum use tabhi discover karte ho jab koi doosri file mysteriously apna content kho baithe.
TASVEER. Figure teen chalk panels mein split hota hai: (left) do files ek tag HEADER_H ke liye lad rahi hain haarne waali greyed out ke saath; (middle) akeli unincluded-twice file "no cost" tick ke saath; (right) #pragma once ek single-line stamp ke roop mein dikhaya gaya "compiler-specific" caveat ke saath.

Ek-tasveer summary
Poori kahani ek frame mein: diamond (main.c → a.h/b.h → types.h), do paste attempts, guard switch, aur outcome — pehli paste rakhi gayi, doosri paste skip hui, exactly ek struct compiler tak pahuncha.

Recall Feynman: poora walkthrough dobara sunao
Ek robot imagine karo jo ek bada binder mein pages copy karta hai teacher ke padhne se pehle. Jab woh "insert page types" dekhta hai, toh woh types page uthata hai aur glue karta hai. Tumhara table of contents ke do routes hain jo dono kehte hain "insert page types" — folder a ke zariye aur folder b ke zariye — toh robot wahi page do baar glue karta hai. Teacher binder kholti hai, Point definition ek baar dekhti hai ("mil gaya"), phir dobara dekhti hai ("ruko, tumne mujhe yeh pehle bhi bataya tha!") aur aage jaane se mana kar deti hai.
Trick: types page par, bilkul upar, hum likhte hain "agar TYPES sticker cover par abhi tak nahi laga, toh use lagao aur yeh page rakho — warna is copy ko phenk do." Pehli baar, koi sticker nahi hai, toh robot use lagata hai aur page glue karta hai. Doosri baar, sticker pehle se laga hai, toh robot duplicate bin karta hai. Teacher ab Point exactly ek baar dekhti hai aur khush hai. Bas dhyan rakho ki har page apna khud ka sticker naam use kare, warna do pages ek doosre ki slot chura lenge.
Recall Quick self-check
Ek unguarded shared header "redefinition" kyun cause karta hai? ::: Har #include ek independent paste hai, isliye ek diamond include path file ki body ko ek translation unit mein do baar paste karta hai, aur ek repeated definition illegal C hai.
#define TYPES_H (bina value ke) ek guard ke andar kya karta hai? ::: Ek nameless flag ko "defined" par flip karta hai taaki baad ka #ifndef TYPES_H false ho jaaye aur doosri paste skip ho jaaye.
#define #ifndef ke turant baad kyun aana chahiye? ::: Taaki flag pehli entry par set ho jaaye, kisi bhi doosri paste ke hone se pehle.
Guard tags har file ke liye unique kyun hone chahiye? ::: Ek shared tag jo bhi header pehle include ho use doosre ko completely block karne deta hai.
Related: Header files and translation units · Compilation pipeline — preprocess, compile, assemble, link · Macros vs inline functions · Conditional compilation for cross-platform code · Build flags -D and the command line · parent Preprocessor directives