printf、scanf 等函數參數個數與類型不固定,C 語言通過 <stdarg.h> 提供的三個宏實現:
va_start(va_list ap, last_fixed):初始化參數指針va_arg(va_list ap, type):按類型取參並推進指針va_end(va_list ap):清理收尾void simple_va_fun(int i, ...) {
va_list ap;
int j = 0;
va_start(ap, i); // i 是最後一個固定參數
j = va_arg(ap, int); // 取第二個參數
va_end(ap);
printf("%d %d\n", i, j);
}
// 調用
simple_va_fun(100); // 輸出 100 隨機值(棧垃圾)
simple_va_fun(100, 200); // 輸出 100 200
simple_va_fun(100, 200, 300); // 僅取前兩個,第三個被忽略
typedef char * va_list;
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
#define va_start(ap, v) (ap = (va_list)&v + _INTSIZEOF(v))
#define va_arg(ap, t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
#define va_end(ap) (ap = (va_list)0)
關鍵點:
&v 是最後固定參數地址va_start 使 ap 指向第一個可變參數va_arg 先按類型對齊推進 ap,再回溯取值va_end 置空指針防誤用va_arg(ap, char*) 實傳 int 導致崩潰printf 那樣通過格式串解析,或約定哨位值va_startva_start(ap),ANSI C 雙參數,頭文件分別為 <varargs.h> / <stdarg.h>優先使用重載、模板、std::initializer_list、std::variant 或 C++20 std::format,避免 C 風格可變參數的不安全性。
摘自 xt_chaoji 的專欄