<stdarg.h> (C89) / <cstdarg> (C++) 提供一組宏,讓函數以統一介面訪問數量/類型不固定的參數列表(...)。
va_start 定位)。| 名稱 | 類型 | 作用 |
|---|---|---|
va_list | 類型 | 保存可變參數掃描狀態的不透明對象 |
va_start(ap, last) | 宏 | 初始化 ap 指向 last 之後的第一個可變參數 |
va_arg(ap, type) | 宏 | 按 type 取出下一個參數,並推進 ap |
va_end(ap) | 宏 | 清理 ap,函數返回前**必須調用** |
va_copy(dest, src) | 宏(C99/C++11) | 複製 va_list,避免多次遍歷失效 |
void func(int fixed, ...) {
va_list ap;
va_start(ap, fixed); // 1. 初始化
// ... 多次 va_arg(ap, type) 獲取參數 ...
va_end(ap); // 3. 必須清理 (匹配 va_start)
}
鐵律:每個va_start必須配對一個va_end,否則行為未定義(棧損壞、內存洩漏)。
PrintFloats第一個參數 amount 指明後續參數個數(約定俗成做法)。
#include
#include
void PrintFloats(int amount, ...) {
va_list ap;
va_start(ap, amount);
printf("Floats passed: ");
for (int i = 0; i < amount; i++) {
double val = va_arg(ap, double); // 注意:float 傳遞會自動提升為 double
printf("\t%.2f", val);
}
va_end(ap);
printf("\n");
}
int main() {
PrintFloats(3, 3.14159, 2.71828, 1.41421);
return 0;
}
FindMax同樣用首參數傳遞個數,首個可變參數作為初始最大值。
int FindMax(int amount, ...) {
va_list ap;
va_start(ap, amount);
int max = va_arg(ap, int); // 至少有一個參數
for (int i = 1; i < amount; i++) {
int val = va_arg(ap, int);
if (val > max) max = val;
}
va_end(ap);
return max;
}
PrintLines不傳個數,用 NULL 指針作為結束標記(類似 execl)。
void PrintLines(char *first, ...) {
va_list ap;
va_start(ap, first);
char *str = first;
do {
printf("%s\n", str);
str = va_arg(ap, char *);
} while (str != NULL);
va_end(ap);
}
// 調用: PrintLines("First", "Second", "Third", NULL);
va_arg 完全信任你傳的 type,傳錯導致未定義行為。float 傳入時會提升為 double,取值必須用 double。printf、哨兵值),C 語言無法自動獲取 ... 參數數量。va_list **不可重用**:遍歷後狀態在末尾,需 va_copy 備份或重新 va_start。char/short → int, float → double。va_arg(ap, char) **錯誤**,必須用 int。variadic templates) 提供類型安全、編譯期展開,優於 stdarg。