C 通過 <stdarg.h> 提供四個宏實現可變參數:
| 宏 | 功能 |
|---|---|
va_list | 類型,保存參數列表信息 (本質是 char* 指針) |
va_start(ap, last) | 初始化 ap 指向 last 參數之後的第一個可變參數 |
va_arg(ap, type) | 取出當前參數 (按 type 解釋),並將 ap 推進到下一個參數 |
va_end(ap) | 清理 ap (置空),釋放資源 |
va_start 計算第一個固定參數地址 + 其對齊後大小,得到第一個可變參數地址。va_arg 根據類型大小 (按 sizeof(int) 對齊) 移動指針並解引用。#include <stdarg.h>
int sum_add(int count, ...) {
va_list ap;
va_start(ap, count);
int sum = 0;
while (count--) {
sum += va_arg(ap, int);
}
va_end(ap);
return sum;
}
// Windows: system("pause");
// Linux:
#include <unistd.h>
void sh_pause() {
rewind(stdin); // 清空輸入緩衝
printf("Press any key to continue...");
getchar();
}
// 通用宏 (atexit 註冊程序退出時自動調用)
#define INIT_PAUSE() atexit(sh_pause)
結論:標準 C 庫的 printf 是線程安全的 (可重入)。
_IO_flockfile / _lock_str) 保護 FILE* 操作。printf 不會導致輸出交織亂序 (每行輸出原子),但不同線程的輸出行順序不確定。printf,或使用無鎖環形緩衝 + 專用日誌線程。int printf(const char *format, ...) {
va_list ap;
va_start(ap, format);
_lock_str2(1, stdout); // 鎖定 stdout 流
int ret = _output_l(stdout, format, NULL, ap); // 核心格式化輸出
_unlock_str2(1, stdout); // 解鎖
va_end(ap);
return ret;
}
核心複雜度在 _output_l (Windows) / vfprintf (Glibc) — 格式字符串解析器 (~2000 行),涉及:
%[flags][width][.precision][length]specifier。va_list 可實現自定義日誌/格式化函數。printf 線程安全但有鎖開銷,熱路徑考慮 fprintf_unlocked (Glibc) 或自行緩衝。printf(user_input) 極度危險,必須用 printf("%s", user_input)。printf (如 minimal 級別) 節省代碼空間。