stdarg.h
<stdarg.h> 提供可变参数函数的实现机制。printf、scanf、sprintf 等函数都使用可变参数。理解可变参数的实现原理,可以编写自己的格式化函数和通用接口。
基本用法
#include <stdarg.h>
#include <stdio.h>
/* 计算平均值 */
double average(int count, ...)
{
va_list args;
va_start(args, count); /* 初始化,count 是最后一个固定参数 */
double sum = 0.0;
for (int i = 0; i < count; i++) {
sum += va_arg(args, double); /* 取下一个 double 参数 */
}
va_end(args); /* 清理 */
return sum / count;
}
/* 使用 */
double avg = average(3, 10.0, 20.0, 30.0); /* 20.0 */
实现 printf 风格函数
#include <stdarg.h>
#include <stdio.h>
void debug_print(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
printf("[DEBUG] ");
vprintf(fmt, args); /* 用 va_list 调用 */
va_end(args);
}
/* 使用 */
debug_print("Value: %d, Name: %s\n", 42, "test");
宏说明
| 宏 | 作用 |
|---|---|
va_list | 声明参数列表变量 |
va_start(ap, last) | 初始化参数列表 |
va_arg(ap, type) | 取下一个参数 |
va_end(ap) | 清理参数列表 |
va_copy(dest, src) | 复制参数列表(C99) |
常见错误
类型不匹配:
int i = va_arg(args, int); /* 正确 */
/* float f = va_arg(args, float); */ /* 错误:float 提升为 double */
float f = va_arg(args, double); /* 正确 */
缺少 va_end:
va_list args;
va_start(args, fmt);
/* 使用 */
/* 忘记 va_end(args); */ /* 资源泄漏 */
参数数量不匹配:
average(3, 10.0, 20.0); /* 声称 3 个参数,只给 2 个 */
/* 未定义行为 */
最佳实践
- 可变参数前必须有至少一个固定参数
- 用固定参数传递类型/数量信息
- 小类型(char、short、float)提升为 int/double
- 始终配对
va_start/va_end - 考虑用 C11
_Generic替代部分可变参数场景