像 printf 这种多参函数, 是借用 stdarg.h 中的宏实现的.
va_list : 用于定义遍历参数列表的指针; va_start : 让指针指向第一个参数; va_arg : 获取下一个参数, 并向后移动一个位置; va_end : 释放指针, 完成遍历.
1. 整数求和:
本例实现了对系列整数求和, 要求至少要有三个参数, 并且最后一个必须是 0.
最后的 0 用于识别列表结束.
#include <stdio.h> #include <stdarg.h> int sum(int n1, int n2, ...) { /* 定义一个指向参数列表的指针, 必须是 va_list 类型 */ va_list p; /* 定义输出变量, 并先获取前两个值 */ int out = n1 + n2; /* 把指针指向最后一个明确的变量 */ va_start(p, n2); /* 用 va_arg 获取下一个整数值, va_arg 会同时把指针向后移动整数大小的位置 */ /* 本例是假定参数都是整数值, 遇 0 终止; 这样在使用是最后一个参数必须是 0 */ while ((n2 = va_arg(p, int)) != 0) out += n2; /* 结束 */ va_end(p); return(out); } int main(void) { printf("%d\n", sum(2,2,2,0)); /* 6 */ printf("%d\n", sum(1,2,3,4,5,6,7,8,9,0)); /* 45 */ getchar(); return 0; }
2. 整数求和(修改版):
这个函数要求至少要两个参数, 最后必须是 0.
#include <stdio.h> #include <stdarg.h> int sum(int n1, ...) { va_list p; int out = n1; va_start(p, n1); while ((n1 = va_arg(p, int)) != 0) out += n1; va_end(p); return(out); } int main(void) { printf("%d\n", sum(2,0)); /* 2 */ printf("%d\n", sum(1,2,3,4,5,6,7,8,9,0)); /* 45 */ getchar(); return 0; }
3. 指定数目的浮点数求和:
该函数参数一指定数目, 之后是列表.
#include <stdio.h> #include <stdarg.h> double sum(int num, double f1, ...) { va_list p; double out = f1; va_start(p, f1); while(--num) { f1 = va_arg(p, double); out += f1; } va_end(p); return(out); } int main(void) { printf("%g\n", sum(3, 1.1, 2.2, 3.3)); /* 6.6 */ printf("%g\n", sum(2, 1.1, 2.2, 3.3)); /* 3.3 */ getchar(); return 0; }
4. 整数与浮点数求和:
本例模拟了 printf 函数的样式, 但只支持整数与浮点数.
#include <stdio.h> #include <stdarg.h> double sum(char *str, ...) { va_list List; double out = 0.0; va_start(List, str); while (*str) { if (*str == '%') { switch (*(++str)) { case 'd': out += va_arg(List, int); break; case 'f': out += va_arg(List, double); break; } } str++; } va_end(List); return(out); } int main(void) { double d = sum("%d,%f,%d,%f", 1, 1.1, 2, 2.2); printf("%g\n", d); /* 6.3 */ getchar(); return 0; }