5.1.29 · D5 · HinglishC Programming
Question bank — Variadic functions — va_list, va_start, va_arg, va_end
5.1.29 · D5· Coding › C Programming › Variadic functions — va_list, va_start, va_arg, va_end
Ye parent note [[Variadic Functions — va_list, va_start, va_arg, va_end|the main topic note]] ka sibling hai. Yahan koi bhari computation nahin hai — sirf reasoning hai.
True or false — justify karo
Compiler ... arguments ko same tarah type-check karta hai jaise named parameters ko karta hai.
False. Jaise hi tum
... likhte ho, compiler types aur counts verify karna band kar deta hai; yahi is feature ki poori cost hai aur UB ke zyaadatar cases ki wajah bhi.va_list guaranteed hai ki ek plain pointer hoga jis par tum arithmetic kar sako.
False. Yeh ek opaque type hai — kuch ABIs par yeh ek struct (ya array!) hota hai jo register-save areas track karta hai, isliye
ap + 1 ya sizeof(ap) meaningless aur non-portable hai.Tum va_list ko normal = assignment se copy kar sakte ho.
False. Kyunki yeh ek array type ho sakta hai,
dst = src fail ho sakta hai ya same cursor ko alias kar sakta hai; iska ekeela portable duplication ==va_copy(dst, src)== hai.Ek variadic function mein legally zero named parameters ho sakte hain, jaise void f(...).
False. C mein at least ek named parameter zaroori hai, kyunki
va_start ko ... ki shuruaat dhundhne ke liye ek anchor naam chahiye hota hai.va_end optional hai agar function waise bhi return hone wala ho.
False. Kuch ABIs
va_start mein cleanup state allocate karte hain; va_end skip karna UB hai, chahe aaj tumhari machine par "kaam" kare.Exactly ek extra va_arg padhna jitne pass kiye gaye the, 0 ya koi harmless default return karta hai.
False. List ke end ko kuch mark nahin karta, isliye extra read baad wale bytes pull karta hai — garbage, koi doosra variable, ya crash. Pure UB.
Ek float pass karna aur use va_arg(ap, float) se padhna sahi hai kyunki types match karte hain.
False. Ek
float pass hone se pehle ==double== mein promote ho jaata hai; float call mein kabhi exist hi nahin karta. Tumhe va_arg(ap, double) se padhna chahiye.printf("%d", 3.5) compiler pakad leta hai kyunki %d clearly ek integer maangta hai.
False. Yeh zyaadatar compile ho jaata hai (shayad warning ke saath); runtime par
%d ek double ke bytes ka int-sized chunk padhta hai → garbage. Format string ko blindly trust kiya jaata hai.Jab tum va_list ko end tak walk kar chuke ho, tum use reset karke dobara walk kar sakte ho.
False. Ek
va_list single-use ho sakta hai, bina kisi rewind ke. Dobara scan karne ke liye tumhe pehle consume karne se pehle va_copy se fresh cursor banana hoga.Named parameter ki apni value pehle va_arg se read back hoti hai.
False.
va_start(ap, last) cursor ko last ke baad position karta hai, isliye pehla va_arg pehla ... argument return karta hai, kabhi last khud nahin.Error dhundho
void log(...) { va_list ap; va_start(ap, ...); } — kya galat hai?
Do errors hain: bare
... ke saath koi named parameter allowed nahin hai, aur va_start ka doosra argument ek naam hona chahiye, ... nahin.char c = va_arg(ap, char); ek argument ke liye jo tumne 'A' pass kiya.
char ko int mein promote kiya gaya tha; char padhna slot ko mis-size karta hai. va_arg(ap, int) use karo phir narrow karo: char c = (char)va_arg(ap, int);.sum(3, 10, 20); jo int sum(int n, ...) call kar raha hai — count 3 kehta hai lekin sirf 2 follow karte hain.
Teesra
va_arg(ap, int) arguments ke baad padhta hai → UB. Count wahi hona chahiye jo actually supply kiya gaya.total_len("a", "b", "c"); ek NULL-sentinel function ke liye.
Caller sentinel
NULL terminate karna bhool gaya, isliye while loop kabhi sentinel nahin dekhta aur end ke baad read karta rehta hai → UB. Caller ko zaroori hai NULL pass kare.va_start(ap, n); return va_arg(ap, int); /* no va_end */
va_end(ap) missing hai — cleanup har path par mandatory hai, early returns aur error branches par bhi.va_copy(ap2, ap); use kiya gaya lekin sirf va_end(ap) call kiya gaya, va_end(ap2) nahin.
Ek copied
va_list apna cursor hai aur use apna va_end(ap2) chahiye; use leak karna UB hai bilkul original ko leak karne ki tarah.va_arg(ap, int*) kuch padhne ke liye jo int array arr ki tarah pass kiya gaya.
Array pointer mein decay ho jaata hai, isliye argument actually ek
int* hai — woh read theek hai; error use int ki tarah padhna hoga. (Trap: mismatch assumption hai, code nahin.)Why questions
Compiler apne aap argument types kyun nahin figure out kar sakta?
Call site par woh actual arguments dekhta hai, lekin function body ke andar sirf
... dikhta hai — va_arg ke consult karne ke liye koi per-call type information kahin store nahin hoti.Standard mechanism ko plain pointer ki jagah macros ke peeche kyun chupaata hai?
Kyunki real layout registers, alignment, aur calling conventions par depend karta hai jo har ABI par alag hota hai; macros tumhara code portable rakhte hain jabki compiler platform ki details fill karta hai.
Small integer types variadically pass hone par int mein kyun promote hoti hain?
Default Argument Promotions
char/short→int aur float→double ko wide karta hai taaki har argument ek uniform, register-friendly size mein aaye — literally koi tarika nahin hai ek un-promoted char transmit karne ka.Ek variadic function ko count ya sentinel kyun chahiye?
Calling convention mein kuch bhi record nahin hota ki kitne arguments aaye, isliye callee ke paas koi intrinsic way nahin hai jaanne ka ki kab rokna hai; tumhe boundary khud encode karni padti hai.
printf ek classic security risk kyun hai?
Yeh arguments strictly format string ke according padhta hai; agar attacker us string ko control karta hai (
printf(user)), toh woh use aise arguments read karwa sakta hai jo kabhi pass hi nahin kiye gaye the, memory leak ya corrupt karke.va_start ko specifically last named parameter jaanna kyun zaroori hai?
Cursor ko exactly wahan se shuru karna hoga jahan named parameters khatam hote hain;
last woh landmark hai jiske baad "is byte ke baad wala byte" pehle variadic argument ka location batata hai.va_arg kabhi verify kyun nahin kar sakta ki tumne jo type maanga woh sahi hai?
Yeh sirf cursor ko tumhare bataye size ke hisaab se aage badhata hai; iske paas koi record nahin hai kya actually push kiya gaya tha, isliye yeh jo bhi bytes wahan hain unhe happily reinterpret kar dega.
Edge cases
Ek variadic function kya karta hai jab zero variadic arguments pass kiye gaye hon (sirf named wala)?
Woh legal hai — tum simply kabhi
va_arg call hi nahin karte. Count/sentinel logic "0 items" case handle karna chahiye (jaise average 0.0 return kare jab n == 0 ho).Kya tum va_list kisi doosre function ko pass karke use va_arg call karwa sakte ho?
Haan, lekin use (ya
va_copy) carefully pass karo — callee ke consume karne ke baad, caller mein cursor position indeterminate ho sakti hai. Isliye vprintf/vsnprintf exist karte hain, jo va_list parameter lete hain.Kya va_arg(ap, struct Foo) by-value pass kiye gaye struct ke liye safe hai?
Yeh defined hai sirf tabhi jab actual argument ka exactly wahi type tha; structs ke liye koi promotion nahin hoti, isliye type pushed struct se exactly match karna chahiye warna UB hai.
Kya hota hai agar tum bina va_end ke va_start do baar call karo?
Undefined behavior — har
va_start ko re-initialise karne se pehle apna va_end chahiye; overlapping starts cleanup state ko corrupt karte hain.Kya va_arg long double padhne ke liye use ho sakta hai?
Haan —
long double promote nahin hota (yeh already sabse wide float hai), isliye tum use exactly va_arg(ap, long double) se padhte ho. Dhyan raho: iska size double se alag hota hai, isliye unhe mismatch karna cursor ko mis-size karta hai.Agar ek function (int a, int b, ...) leta hai, toh va_start(ap, b) kahan se start karta hai?
b ke baad, jo last named parameter hai — a aur b dono skip ho jaate hain, aur pehla va_arg pehla ... argument return karta hai.Ek sentinel ki tarah (void*)0 vs bare 0 pass karna hamesha safe hai?
Hamesha nahin — bare
0 int ki tarah pass ho sakta hai, lekin reader pointer width expect karta hai. Un platforms par jahan yeh alag hote hain, yeh mismatch karta hai; pointer size force karne ke liye (void*)NULL ya (char*)NULL use karo.