Visual walkthrough — Undefined behavior — comprehensive list, why to avoid
5.1.30 · D2· Coding › C Programming › Undefined behavior — comprehensive list, why to avoid
Hum ye assume nahi karenge ki tum jaante ho compiler, overflow, ya "sequence point" kya hota hai. Har word ko ek picture milegi.
Step 1 — Compiler actually kya hota hai (the contract picture)
KYA HAI. Ek compiler ek translator hai. Tum use C source text dete ho; woh tumhe machine instructions deta hai (actual 1s aur 0s jo CPU chalata hai). Use ek bahut literal-minded factory worker ki tarah socho.
YE PEHLE KYUN. Tum samajh nahi sakte ki code delete kaise hota hai jab tak tum ye na dekho ki compiler allowed hai jo tum ne likha use change karne ki, jab tak visible result wahi rahe jo C standard promise karta hai. Standard hi contract hai. Compiler tumhe sirf wahi outputs deta hai jo contract list karta hai.
PICTURE. Left mein, tumhara source. Beech mein, contract (C standard) jo filter karta hai ki compiler ko kya preserve karna hai. Right mein, machine code — jo tumhare source se chhota ho sakta hai agar contract usse kuch kaam skip karne de.

Step 2 — Woh number line jis par har int rehta hai
KYA HAI. Ek signed int ek whole number hai jo bits ki ek fixed number mein store hota hai — zyaadatar machines par 32 bits. Iska matlab hai ye sirf ek finite range mein values rakh sakta hai. Sabse bade wale ko hum INT_MAX kehte hain.
KYUN. Hamara poora example isi ke baare mein hai ki kya hota hai jab ek number us range ke edge se aage jaane ki koshish karta hai. Toh pehle hume woh edge dekhni hai.
PICTURE. Ek number line jo hamesha ke liye nahi jaati. Ye right mein INT_MAX par ruk jaati hai (aur left mein INT_MIN par). Har end par ek wall hai.

Ye limits kahan se aati hain, ye dekhne ke liye Integer Types and Overflow dekho.
Step 3 — "Overflow" ka matlab kya hai, aur raste ka fork
KYA HAI. Overflow tab hota hai jab ek calculation aisa result produce karta hai jo Step 2 ki walls ke bahar land karta. INT_MAX + 100 ek aise number banana chahta hai jo sabse bade int se bada ho.
YE CRUX KYUN HAI. Yahaan C contract ek fateful split karta hai:
- Unsigned integers ke liye, overflow defined hai — ye ek ghadi ki tarah wrap around karta hai (mod ). Bilkul legal.
- Signed integers ke liye, overflow undefined hai — contract bilkul kuch nahi kehta.
PICTURE. Do number lines. Unsigned wali ek circle (ghadi) mein bend ho jaati hai — top se aage jaao aur bottom pe loop ho jaate ho. Signed wali bas... ek cliff se "???" ki dhund mein gir jaati hai.

Step 4 — Key assumption: "UB kabhi nahi hota"
KYA HAI. Ye woh single sentence hai jo poori trick ko power deta hai. Kyunki signed overflow undefined hai, compiler haqdar hai ye assume karne ka ki tumhara program kabhi ise trigger nahi karta. "Gracefully handle karta hai" nahi — assume karta hai ki ye impossible hai.
COMPILER KO ALLOWED KYUN HAI. Step 1 phir se padho: compiler correct output sirf un programs ke liye deta hai jo contract maante hain. Ek program jo signed int overflow karta hai contract pehle se chhod chuka hai, toh compiler use kuch nahi deta — aur us path ko dead code ki tarah treat kar sakta hai jo kabhi execute nahi ho sakta.
PICTURE. Compiler blinders pahne hua: har branch jo signed overflow require karta hai woh "unreachable" ke roop mein grey ho gayi hai. Use literally woh paths real nahi dikhte.

Step 5 — Promise ko x + 100 < x par apply karo
KYA HAI. Ab parent note ka actual check lo. Hum poochhte hain: "no overflow" ke promise ke saath, kya x + 100 < x kabhi true ho sakta hai?
KYUN. Hum compiler ki algebra dekhna chahte hain, kyunki uska agla move completely isi answer par depend karta hai.
Defined world ke andar reason karo (jahaan koi overflow nahi hota). Phir ordinary school algebra apply hoti hai: dono taraf se subtract karo.
PICTURE. Condition box collapse hoti hui: do inputs (x+100 aur x) ek comparison ko feed karte hain jise compiler ek single stamped tile mein rewrite karta hai jis par FALSE likha hai.

Step 6 — Branch delete karna (vanishing check)
KYA HAI. if (false) return -1; apna body kabhi run nahi kar sakta. Toh compiler poora if aur uska return -1; remove kar deta hai. Tumhara overflow check machine code se chala gaya.
YE LEGAL KYUN HAI, BUG NAHI. As-if rule (Step 1) ke hisaab se, woh code delete karna jo provably kabhi execute nahi hota koi observable behaviour nahi badlata ek contract-obeying program ke liye. Compiler correct hai. Tum ne overflow par rely karke contract toda.
PICTURE. Machine code ka before/after. Red "safety check" block crossed out hai; arrow seedha return x + 100 par jaata hai.

Step 7 — Fix: defined domain mein reason karo
KYA HAI. Check ko rewrite karo taki addition tab kabhi na ho jab tak safe na ho. Jodhne se pehle compare karo.
YE KYUN KAAM KARTA HAI. INT_MAX - 100 hamesha range mein hota hai (max se subtract karna overflow nahi kar sakta). Toh comparison sirf legal arithmetic use karta hai — koi promise nahi toota, kuch bhi "always false" nahi hai, aur compiler ko branch rakhna hi hoga.
PICTURE. Step 2 ki number line INT_MAX - 100 par ek marker ke saath. Wall se aage koi bhi x pehle se flag ho jaata hai kabhi bhi wall cross karne ki koshish karne se pehle.

Step 8 — Degenerate aur neighbour cases (kuch bhi uncovered nahi chhhoda)
KYA / KYUN. Wahi "assume UB is impossible" engine har category ko drive karta hai parent note se. Har degenerate input ka same shape hai: ek value jo contract chhod deti hai, aur ek compiler jo pretend karta hai ki woh nahi kar sakti.
PICTURE. Edge cases ka ek dashboard, har ek input aur compiler ki silent assumption dikhata hua.

| Degenerate input | Ye UB kyun hai | Compiler kya assume karta hai |
|---|---|---|
x / 0, x % 0 |
division by zero ki koi value nahi | ye divisor kabhi zero nahi → zero-checks delete kar sakta hai |
INT_MIN / -1 |
result INT_MAX se zyada hai |
signed overflow → kabhi nahi hota |
x << 32 (32-bit) |
shift count width UB hai | count hamesha mein hai |
*p jab p == NULL |
null deref UB hai | p non-null assume kiya → ek baad wala if (p) check delete ho sakta hai |
i = i++; |
do writes, koi [[Sequence Points and Operator Precedence | sequence point]] nahi |
Ek-picture summary

Poori chain compressed: tumhara promise → compiler ka assumption → constant-folding → branch deletion → runtime garbage — fix branch ke saath jo kabhi pipeline mein nahi jaati.
Recall Feynman retelling — ek 12-saal ke bachche ko batao
Socho tum ek super-fast worker (compiler) hire karte ho aur use ek rulebook (C standard) dete ho. Rulebook kehta hai: "Kuch cheezein itni forbidden hain ki agar koi customer kabhi unhe maange, tum assume kar sakte ho koi customer kabhi nahi maangega." Signed-number overflow unhi mein se ek hai.
Tum likhte ho: "AGAR 100 jodhne se mera number chhota ho jaaye, alarm bajao." Lekin chhota hona sirf overflow se ho sakta hai — ek forbidden cheez. Toh worker reason karta hai: "100 jodhne se chhota hona forbidden hai, toh ye kabhi nahi hota, toh alarm kabhi nahi bajega, toh main time save karne ke liye alarm tod ke phenk dunga." Woh tumhe ek machine deta hai koi alarm nahi wali.
Phir ek real customer number overflow karta hai. Woh quietly garbage ban jaata hai, aur woh alarm jo tumne carefully install kiya tha gone hai — worker ne use dukaan khulne se pehle remove kar diya tha. Fix: apna alarm kabhi forbidden cheez ke terms mein frame mat karo. "Kya ye overflow hua?" ke bajaye poochho "kya ye hone wala hai?" — pehle x > INT_MAX - 100 check karo, sirf legal math use karke. Woh alarm worker rakhne par majboor hai.
Recall Quick self-test
if (x + 100 < x) delete kyun hota hai lekin if (x > INT_MAX - 100) nahi? ::: Pehla signed overflow (UB) par rely karta hai toh compiler prove karta hai ye always false hai aur ise remove karta hai; doosra sirf in-range arithmetic use karta hai, toh ye ek real, non-constant branch hai.
Kya ek baad wali line ka UB ek pehli line change kar sakta hai? ::: Haan — compiler "ye kabhi nahi hota" assumption ko backwards propagate karta hai, jaise ek pehle wala if (p) delete karna kyunki baad wala *p imply karta hai p non-null hai.
Kya signed overflow wrap karta hai? ::: Hardware par aksar haan, lekin compiler ko iska honour karna zaroori nahi — ye UB hai, toh woh optimize kar sakta hai jaise ye kabhi nahi hota.
Related build-up: Pointers and Memory in C · malloc and free — Dynamic Memory · Strict Aliasing Rule.