5.1.29 · HinglishC Programming

Variadic functions — va_list, va_start, va_arg, va_end

1,928 words9 min readRead in English

5.1.29 · Coding › C Programming


WHY — iska zaroorat hi kyun hai?

Is power ki cost: compiler aapko check karna band kar deta hai. Sirf aap decide karte ho ki kitne args hain aur har ek ka type kya hai. Galat promise kiya → undefined behavior.


WHAT — chaar pieces kya hain?


HOW — pehle principles se kaise kaam karta hai

Jab aap f(a, b, c, d) call karte ho, toh arguments kahin aisa rakhe jaate hain jahan callee reach kar sake (bahut se ABIs mein: stack aur/ya registers mein, ek known order mein). Named parameters pehle slots consume karte hain. Baaki bytes wahan hain lekin unnamed.


Figure — Variadic functions — va_list, va_start, va_arg, va_end

Worked Example 1 — n integers ka sum (count method)

#include <stdarg.h>
#include <stdio.h>
 
int sum(int n, ...) {          // n tells us HOW MANY follow
    va_list ap;
    va_start(ap, n);           // cursor starts after 'n'
    long total = 0;
    for (int i = 0; i < n; i++)
        total += va_arg(ap, int);   // pull each as int
    va_end(ap);
    return (int)total;
}
 
int main(void){ printf("%d\n", sum(3, 10, 20, 30)); }  // 60
Step Code Yeh step kyun?
1 int sum(int n, ...) Ek named param n chahiye taaki va_start ko anchor mile aur hum count jaanein.
2 va_start(ap, n) Cursor ko n ke theek baad — pehle ... argument par — point karo.
3 va_arg(ap, int) in loop Exactly n times padho aur aage badho; type int usi se match karta hai jo humne pass kiya.
4 va_end(ap) Return karne se pehle required cleanup.

Worked Example 2 — sentinel-terminated string concatenator

#include <stdarg.h>
#include <string.h>
 
size_t total_len(const char *first, ...) {
    va_list ap;
    va_start(ap, first);
    size_t len = strlen(first);
    const char *s;
    while ((s = va_arg(ap, const char*)) != NULL)  // stop at NULL
        len += strlen(s);
    va_end(ap);
    return len;
}
// total_len("ab", "cde", "f", NULL) == 6
Step Yeh step kyun?
first is named Anchor milta hai; aur yahan yeh natural bhi hai (list mein hamesha ek pehla item hota hai).
loop until NULL Koi count pass nahi kiya gaya, toh ek sentinel end mark karta hai. Caller ko NULL zaroor pass karna hoga.
va_arg(ap, const char*) Humne pointers promise kiye — type args se match karni chahiye.

Worked Example 3 — va_copy se re-scanning

double average(int n, ...) {
    va_list ap, ap2;
    va_start(ap, n);
    va_copy(ap2, ap);          // duplicate cursor BEFORE consuming
 
    long sum = 0;
    for (int i = 0; i < n; i++) sum += va_arg(ap, int);
    va_end(ap);
 
    // ... could re-walk ap2 for a second pass ...
    va_end(ap2);
    return n ? (double)sum / n : 0.0;
}

Common Mistakes (Har ek ko Steel-man karo)


Recall Feynman: 12-saal ke bachche ko samjhao

Socho ek conveyor belt hai jisme boxes aa rahe hain, aur tum shuru mein khade ho. Tumhe nahi pata kitne boxes aa rahe hain. va_start kehta hai "pehle box par jao." va_arg(int) kehta hai "agla box kholo, expect karo ki ek number hai, use lo, aur agle box par chale jao." Lekin yahan trick hai: belt tumhe nahi batati ki kab khatam hoti hai aur boxes par label nahi hota ki andar kya hai. Isliye pehle se agree karna hota hai — ya toh koi batata hai "3 boxes hain," ya aakhri box ek special khaali "STOP" box hota hai. Agar count ya contents galat guess karo, toh haath mein kuch nahi aata. va_end hai jab kaam ho jaata hai toh haath neeche karna.


Active Recall

Variadic macros kaunsa header declare karta hai?
<stdarg.h>
va_list kya hai?
Ek opaque type jo argument list mein current position (cursor) hold karta hai.
va_start(ap, last) kya karta hai?
ap ko aakhri named parameter last ke theek baad point karne ke liye initialize karta hai.
va_arg(ap, type) kya karta hai?
Agla argument type ke roop mein interpret karke return karta hai, aur cursor ko aage badhata hai.
va_end kyun call karna zaroori hai?
Yeh va_list ka required cleanup karta hai function return karne se pehle.
Ek variadic function mein ≥1 named parameter kyun hona chahiye?
va_start ko apne anchor point ke roop mein aakhri named parameter ka naam chahiye hota hai.
Kitne variadic args hain yeh jaanne ke do tarike?
Ek count argument, ya ek sentinel terminator value (jaise NULL/-1).
float arguments mein kaunsa promotion hota hai?
Unhe double mein promote kiya jaata hai, isliye va_arg(ap, double) use karo.
char/short arguments mein kaunsa promotion hota hai?
Unhe int mein promote kiya jaata hai, isliye va_arg(ap, int) use karo.
va_copy(dst, src) kis kaam aata hai?
va_list ko portably duplicate karne ke liye taaki arguments ek se zyada baar scan kiye ja sakein.
va_arg type mismatch se UB kyun hota hai?
Bytes ko galat type / galat size ke roop mein interpret kiya jaata hai, garbage memory padhi jaati hai.
Kya va_list ko rewind kar sakte hain?
Nahi — yeh effectively single-pass hota hai; agar doosra pass chahiye toh pehle va_copy se copy karo.

Connections

Concept Map

motivates

uses

requires

includes

passed to

initializes

read by

advances

closed by

needs stop rule

cost

type mismatch causes

C99 duplicate

Unknown arg count at runtime

Variadic function

stdarg.h macros

≥1 named parameter

va_list cursor

va_start ap last

va_arg ap type

va_end ap

Count or sentinel

Compiler stops checking

Undefined behavior

va_copy