C 語言無函數多載,stdarg.h 提供的 va_list、va_start、va_arg、va_end 四巨集,讓函數能在執行期走訪呼叫者堆疊上的可變參數。本文解析底層原理、標準使用流程、終止條件設計與型別安全陷阱。
#include <stdarg.h>
void demo(int fixed, ...) { // 至少一個固定參數
va_list ap; // 1. 宣告迭代器
va_start(ap, fixed); // 2. 定位至第一個可變參數
while (/* 條件 */) {
int val = va_arg(ap, int); // 3. 取值並推進
// 處理 val
}
va_end(ap); // 4. 清理(部分實作為空巨集)
}
// 簡化版定義
#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 之後即為可變參數。_INTSIZEOF 將大小對齊至 sizeof(int) 倍數(呼叫慣例要求)。va_arg 先推進指標再回傳原位址內容,實現「取值並前進」。| 模式 | 適用場景 | 範例 |
|---|---|---|
| 哨兵值 | 同型別參數,有明確無效值 | printf("%d", -1) 結束 |
| 計數參數 | 第一個固定參數傳入參數個數 | sum(3, 1,2,3) |
| 格式字串 | 異質參數,掃描格式字串決定型別/個數 | printf("%d %s", 1, "hi") |