Visual walkthrough — Variadic functions — va_list, va_start, va_arg, va_end
5.1.29 · D2· Coding › C Programming › Variadic functions — va_list, va_start, va_arg, va_end
Hum sirf ek cheez jaante hain maan ke chalte hain: computer ki memory ek lambi row hai numbered mailboxes ki, har ek mein ek byte hota hai, aur har ek ka ek address hota hai (uska ghar ka number). Baaki sab hum khud build karte hain.
Step 1 — "Arguments on the stack" ka asli matlab
YEH picture kyun: aap kisi cheez ke upar "cursor walk" nahi kar sakte jo dikhti hi nahi. Kisi bhi macro ke samajh aane se pehle, hume woh row of bytes dekhni hogi jiske upar cursor chalta hai. Hum ek simplified all-on-the-stack model use karte hain (real CPUs registers bhi use karte hain — yahi complexity hai jise macros chhupaate hain, dekho Calling Conventions and the Stack).
PICTURE: har int 4 bytes wide hota hai. Toh chaar arguments ek strip mein addresses occupy karte hain. Named parameter n bilkul pehla block hai; ... values uske baad aati hain.

Step 2 — Cursor sirf ek number hota hai
Pointer kyun, koi index kyun nahi? Kyunki arguments real memory addresses pe rehte hain, aur pointer C ka native tool hai "ek address hold karo aur jo wahan hai use padho" ke liye. Ek index ko add karne ke liye ek base chahiye hoga; ek pointer already hai base+offset ek value mein. Yeh is kaam ke liye minimal tool hai.
PICTURE: ko ek chhoti si arrow socho jo memory strip ke upar floating hai, ek byte ke upar parked hai.

- — cursor ki current position (ek address, yani ek number).
- Koi length kaheen store nahi hoti. jaanta hai kahan hai, kabhi nahi kitna aage ja sakta hai. Yeh yaad rakho — yahi poora reason hai ki hume ek count ya sentinel chahiye.
Step 3 — va_start: cursor ko last named arg ke baad park karo
"n ke baad" kyun? Named parameters woh slots hain jo compiler ne reserve kiye aur name diye. n aakhri hai jise aapne naam diya. Jo kuch aap read karna chahte hain woh sab iske aage hai. Toh cursor ki starting line named region ki finish line hai.
PICTURE: n ke baad ka address hai . Humare conceptual model mein:

Green arrow ab pehle ... value (10) pe baith gaya hai. Humne abhi kuch read nahi kiya — sirf aim kiya hai.
Step 4 — va_arg: yahan padho, phir aage badho
Read-then-advance kyun (aur TYPE aap kyun batate ho)? Memory ke bytes sirf bits hain — unpe koi label nahi likha "main ek int hoon" ya "main ek pointer hoon." Koi toh decide kare ki inhe kaise interpret karna hai. Compiler ne ... pe checking band kar di, toh aap type dete ho. va_arg(ap, int) matlab hai "trust karo mujhe: agle 4 bytes ek int hain."
PICTURE — 10 nikalna: cursor 10 block ke upar hai. Hum woh 4 bytes ek int ke roop mein copy karte hain, phir cursor ko sizeof(int) = 4 se daayein slide karte hain.

- — " ko aise treat karo jaise woh ek int ki taraf point kar raha ho."
- — star ka matlab hai "mujhe woh value do jo us address pe rehti hai."
- — read karne ke baad, cursor ko abhi consume ki gayi width se aage move karo, taaki agla
va_argfresh start kare.
va_arg(ap, int) do baar aur call karo aur aap 20, phir 30 le lete ho, cursor har baar 4 bytes step karta hai.
Step 5 — Type kyun promoted type honi chahiye
KYU: koi value ... tak pahunchne se pehle hi, C Default Argument Promotions apply karta hai: har char/short ko int mein widen kar diya jaata hai, aur har float ko double mein widen kar diya jaata hai. Narrow value actually kabhi arguments mein rakhi hi nahi jaati — uski ek moti copy rakhi jaati hai. Toh byte-strip mein actually ints aur doubles hote hain, chahe aapne call pe kuch bhi likha ho.
PICTURE: caller ka char c = 'A' ek 4-byte int slot ban jaata hai; float x ek 8-byte double slot ban jaata hai. Agar aapka cursor sirf 1 ya 4 bytes read karne ki koshish kare, toh woh value ke beech mein land karta hai aur baad ke har read misaligned ho jaata hai.

Step 6 — Degenerate case: ek zyaada baar read karna
Yeh sirf galat nahi, fatal kyun hai: last argument ke baad jo bhi stack mein tha — return address, saved registers, garbage — wahi hota hai. Use int ke roop mein interpret karna bakwaas number deta hai; program junk print kar sakta hai ya crash ho sakta hai. Yeh textbook Undefined Behavior in C hai.
PICTURE: strip 30 ke baad khatam ho jaati hai. Chautha va_arg red "no-man's-land" mein jaata hai.

Yahi reason hai ki har variadic function ko ek stop rule chahiye:
- ek count (
sum(3, ...)— exactly 3 padho), ya - ek sentinel (ek final
NULL/-1jo kehta hai "STOP").
Machinery mein kuch bhi enforce nahi karta — discipline poori tarah aapki hai.
Step 7 — va_end: cursor ko neeche rakho
Agar waise bhi return kar rahe hain toh zahmat kyun? Kyunki standard ise require karta hai, aur kuch calling conventions mein va_start temporary state allocate karta hai jo release na ho toh leak ya corrupt ho jaata hai. va_start aur va_end ko ek matched pair ki tarah treat karo, jaise bracket kholna aur band karna.
PICTURE: arrow retire ho gaya; strip untouched hai.

Ek-picture summary
Upar sab kuch, ek strip pe: last named arg ke baad park karo → read+step, read+step, read+step → agreed boundary pe ruko → cursor retire karo.

Recall Feynman: poori walk simple words mein
Ek shelf pe parcels ki row socho, left se right. Pehle parcel pe n likha hai — woh aapko bataya gaya tha. Aapka kaam hai iske baad ke unlabelled parcels kholna, lekin kisi ne nahi likha andar kya hai ya kitne hain.
va_start aapki ungli n parcel ke theek daayein rakhta hai — pehle mystery parcel pe.
va_arg(int) matlab hai "mujhe lagta hai is parcel mein ek certain size ka number hai; ise kholo, number lo, aur apni ungli exactly us size se daayein karo." Aapko size pata honi chahiye, kyunki parcels unlabelled hain — aur shelf secretly chhote parcels ko mota kar deti hai (ek char ek full-size int box ban jaata hai, ek float ek double box ban jaata hai) rakhne se pehle, toh hamesha mote size pe bet lagao.
Shelf ka koi end marker nahi hai. Agar aap ek parcel zyaada khol lo, toh aap shelf ke baad ki empty air pakad rahe ho — yehi crash hai. Toh ya toh aapko bataya gaya "3 hain," ya aakhri parcel ek special empty STOP box hai.
va_end kaam khatam hone pe apna haath neeche karna hai. Start, phir Arg-Arg-Arg, phir End. Yahi poora dance hai.
Active Recall
va_start cursor ko kahan park karta hai?
... argument.va_arg ko type batane ki zaroorat kyun hai?
va_arg kya do kaam karta hai?
Ek extra va_arg read karna undefined behavior kyun hai?
float/char pass karne par bhi double/int kyun likhna padta hai?
float→double aur char/short→int ko mota kar deti hain isse pehle ki woh kabhi ... tak pahunchen.va_end kya karta hai aur yeh required kyun hai?
va_start mein state allocate karti hain jise release karna zaroori hai.