printf 等函数可接受数量不定的实参,称为变参函数(variadic function)。实现变参函数需使用 stdarg.h 中的 va_list、va_start、va_arg、va_end。变参的格式解析与格式说明符密切相关。
变参函数声明
除至少一个固定参数外,使用省略号 ... 表示后续还可传入更多参数:
return_type name(fixed_arg, ...);stdarg.h 中的四个步骤
- 1. va_list
- 声明参数列表遍历用的变量。
va_list list;- 2. va_start()
- 初始化列表;第二个实参为最后一个固定形参名,用于定位变参起始位置。
va_start(list, fixed_arg);- 3. va_arg()
- 按指定类型取下一个变参;类型须与实参一致。
va_arg(list, type);- 4. va_end()
- 结束对列表的使用。
va_end(list);示例:打印若干个整数
第一个固定参数 n 表示后续整数的个数:
#include <stdio.h>
#include <stdarg.h>
void print(int n, ...) {
va_list args;
va_start(args, n);
for (int i = 0; i < n; i++)
printf("%d ", va_arg(args, int));
printf("\n");
va_end(args);
}
int main(void) {
print(3, 1, 2, 3);
print(5, 1, 2, 3, 4, 5);
return 0;
}输出:
1 2 3
1 2 3 4 5变参函数无法自行得知变参个数,须由调用方通过计数参数、哨兵值或格式串等方式约定,printf 即通过格式串中的说明符确定类型与数量。
示例:求和
#include <stdarg.h>
#include <stdio.h>
int getSum(int n, ...) {
int sum = 0;
va_list list;
va_start(list, n);
for (int i = 0; i < n; i++)
sum += va_arg(list, int);
va_end(list);
return sum;
}
int main(void) {
printf("1 + 2 = %d\n", getSum(2, 1, 2));
printf("3 + 4 + 5 = %d\n", getSum(3, 3, 4, 5));
printf("6 + 7 + 8 + 9 = %d\n", getSum(4, 6, 7, 8, 9));
return 0;
}示例:混合类型
#include <stdio.h>
#include <stdarg.h>
void print(int n, ...) {
va_list args;
va_start(args, n);
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
printf("Integer: %d\n", va_arg(args, int));
} else {
printf("Float: %.2f\n", va_arg(args, double));
}
}
va_end(args);
}
int main(void) {
print(4, 10, 3.14, 20, 2.71);
return 0;
}注意事项
va_arg的类型须与传入实参一致;float在变参中按默认实参提升为double,应以double读取。- 读取次数不得超过实际传入的变参个数,否则为未定义行为。
- 每个
va_start应配对一次va_end。
本节介绍了变参函数的声明与 stdarg.h 用法。下一节讨论在错误路径上使用goto 集中清理资源的写法。