C 語言透過 `
| 巨集 | 說明 |
|---|---|
va_list ap | 宣告參數列表遍歷器 |
va_start(ap, last_named_param) | 初始化 `ap` 指向第一個可變參數 |
va_arg(ap, type) | 取得目前參數值並推進 `ap` |
va_end(ap) | 結束遍歷,清理資源 |
double average(int count, ...) {
va_list ap;
va_start(ap, count);
double sum = 0;
for (int i = 0; i < count; i++)
sum += va_arg(ap, double); // 參數預設提升為 double
va_end(ap);
return sum / count;
}
int max_of(int count, ...) {
va_list ap;
va_start(ap, count);
int max = va_arg(ap, int); // 至少有一個參數
for (int i = 1; i < count; i++) {
int val = va_arg(ap, int);
if (val > max) max = val;
}
va_end(ap);
return max;
}
#include#include // 遞迴輸出整數 void print_int(int n) { if (n < 0) { putchar('-'); n = -n; } if (n >= 10) print_int(n / 10); putchar('0' + n % 10); } void my_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); while (*fmt) { if (*fmt == '%') { fmt++; switch (*fmt) { case 'd': { int val = va_arg(ap, int); print_int(val); break; } case 'c': { int val = va_arg(ap, int); // char 提升為 int putchar(val); break; } case 's': { char *s = va_arg(ap, char *); if (!s) s = "(null)"; while (*s) putchar(*s++); break; } case '%': putchar('%'); break; default: putchar('%'); putchar(*fmt); // 未知格式原樣輸出 } } else { putchar(*fmt); } fmt++; } va_end(ap); } int main() { my_printf("Hello %s! Num=%d, Char=%c, %%\n", "World", 42, 'X'); return 0; }
// 解析 %[flags][width][.precision][length]specifier // 範例:%08lx -> flags='0', width=8, length='l', specifier='x' // 需建立狀態機解析格式字串,再根據 length 選擇 va_arg 型別: // hh -> char, h -> short, l -> long, ll -> long long, z -> size_t, t -> ptrdiff_t
可變參數是 C 語言實現 `printf`、`scanf`、`execl` 等函式的基石。掌握 `va_list` 四巨集操作、預設參數提升規則、格式字串解析邏輯,不僅能手寫格式化函式,更能深入理解 C 呼叫慣例與堆疊幀佈局,為除錯、逆向工程、編譯器開發打下堅實基礎。