可變參數(variable argument)讓函式能接受不定數量、不定型別的引數。宣告時以 ... 標示,例如 void func(int fixed, ...);。其彈性極高,但也帶來型別安全缺失、參數解析複雜等挑戰。
x86 平台採「由高址向低址」配置記憶體,參數由右至左壓入堆疊,確保堆疊頂端(低址)為第一個固定參數。以 fun(int var1, int var2, ..., int var3, int var4) 為例:
堆疊區(低址 → 高址): | 堆疊頂 低址 | 第一個固定參數 var1 | 可變參數前的固定參數 var2 | 可變參數第 1 個 | ... | 可變參數最後一個 | 倒數第二個固定參數 var3 | 最後一個固定參數 var4 | ... | 函式回傳位址 | ... | 堆疊底 高址
此佈局是 va_start/va_arg 能正確遍歷參數的硬體基礎。
<stdarg.h>)typedef void *va_list; // 參數指標型別
va_start(ap, parmN); // 初始化 ap 指向第一個可變參數
va_arg(ap, type); // 取得當前參數並推進 ap 至下一個
va_end(ap); // 結束遍歷(某些平台需清理)
parmN:可變參數前的最後一個固定參數,作為定位錨點。type:呼叫端需自行指定欲讀取的型別,編譯器不做型別檢查。#include
#include
void tVarArg(int num, ...) { // num 為可變參數個數(約定俗成)
va_list argp;
va_start(argp, num);
while (num-- > 0) {
printf("%s", va_arg(argp, char*)); // 必須知道每個參數是 char*
}
va_end(argp);
}
int main() {
tVarArg(5, "Hello! ", "My ", "name ", "is ", "neverTheSame.");
tVarArg(8, "This ", "is ", "an ", "example ", "about ", "variable-argument ", "in ", "function");
return 0;
}
...。va_start(ap, parmN) 的 parmN 必須是緊鄰 ... 前的固定參數。printf 透過格式字串解析,自行實作需自訂協定(如第一個參數給個數、或特定終止標記)。va_arg(ap, type) 直接強制轉型,傳錯型別導致未定義行為。C++11 起推薦使用可變參數樣板(variadic templates)配合 std::initializer_list、std::tuple 或折疊運算式,提供型別安全、編譯期檢查的替代方案。僅在需相容 C API 或極度動態場景才使用傳統 va_list。