1、基础认识
C语言不同C++,Java等面向对象的语言一样具有重载功能。所以如果要在解决同名不同参数的函数上困难重重,变长参数意味着函数处理数据具有不确定性。即使是用C++重载也是一个繁琐的事情。
C语言标准库<stdarg.h>定义了变长参数的使用。<stdarg.h>定义一个变量类型va_list和三个宏函数va_start(),va_arg(),va_end(),va_copy()。
1)va_list ap:定义一个指向可选参数的指针ap。
2)va_start(ap, valuec):初始化可变参数,使指针ap指向函数可变参数的第一个参数,同时valuec位于函数参数列表可变参数前的参数,确定可变参数的个数。
3)va_arg(ap, type):逐个取出参数,type为参数的类型。
4)va_end(ap):结束可变参数,释放资源。
注意:可变参数一定要在函数参数列表的末尾,和默认参数一样。
1 #include <stdio.h> 2 #include <stdarg.h> 3 4 int average(int, ...); 5 6 int main() 7 { 8 printf("%d\n", average(5, 1, 2, 3, 4, 5)); 9 10 return 0; 11 } 12 13 int average(int valuec, ...) { 14 15 int i, ave = 0; 16 va_list ap; /* 定义va_list变量ap */ 17 18 va_start(ap, valuec); /* 初始化变量ap */ 19 20 printf("%d\n", valuec); 21 printf("%d\n", ap); 22 23 for(i = 0; i < valuec; i++) { 24 ave += va_arg(ap, int); /* 取出参数 */ 25 } 26 va_end(ap); /* 结束变量ap */ 27 28 return ave / valuec; 29 } 30 31 /* 32 * 输出3 33 */
分析:由上面的例子可以知道可变参数的一般用法。
猜想:va_list声明的指针ap。va_start(ap,valuec)使指针ap指向第一个可变参数。va_arg(ap,type)逐个取出参数,作指针运算。va_end(ap)释放资源,类似free(ap)。
而va_copy(va_list dest, va_list src)复制src到dest。可以在va_start(ap, valuec)之后使用,类似复制指针。
2、进阶认识
1)在linux下man了一下函数va_copy()。发现一个函数例子:
1 #include <stdio.h> 2 #include <stdarg.h> 3 4 void foo(char *, ...); 5 6 int main() 7 { 8 char name[20] = "huangzijian"; 9 char a = 'a'; 10 int i = 2333; 11 12 13 foo("scd", name, a, i); 14 15 return 0; 16 } 17 18 void foo(char *fmt, ...) { 19 va_list ap; 20 int d; 21 char c, *s; 22 23 va_start(ap, fmt); 24 while (*fmt) 25 switch (*fmt++) { 26 case 's': /* string */ 27 s = va_arg(ap, char *); 28 printf("string %s\n", s); 29 break; 30 case 'd': /* int */ 31 d = va_arg(ap, int); 32 printf("int %d\n", d); 33 break; 34 case 'c': /* char */ 35 /* need a cast here since va_arg only 36 takes fully promoted types */ 37 c = (char) va_arg(ap, int); 38 printf("char %c\n", c); 39 break; 40 } 41 va_end(ap); 42 } 43 44 /* 45 * string huangzijian 46 * char a 47 * int 2333 48 */
分析:上面的例子给了我们一个灵感,是否可以实现类似的printf和scanf函数。scanf函数容易实现,与上面如出一辙;但是printf函数就是在其他的字符上进行原字符输出。