va_list是 C 语言专门用来解决可变参数问题的工具,于 C99 标准引入,尽管很早从一些书上阅读过有关的内容,但是一直没有整理,这次整理下。
如何使用
由于va_list是 C 语言标准提供的接口,所以支持 C99 标准的 C 编译器都支持相关功能。使用时,需要先引入头文件:1
这个头文件里声明了一个类型va_list和针对这个类型的四个常用宏:va_start、va_arg、va_end和va_copy。
va_start
原型:1
void va_start(va_list ap, last);
功能:初始化一个va_list类型的变量ap。
参数:ap是一个va_list类型的变量,实际是一个指针,指向可变参数列表的第一个参数;last是参数列表之前的最后一个参数,被调用函数一定知道这个参数的类型,且这个参数不能声明为register,也不能是一个函数或数组。同时,这个参数还可以用于向函数传递一些信息,比如元素的个数,格式化字符串等。
va_arg
原型:1
type va_arg(va_list ap, type);
功能:从已初始化的va_list变量中取出下一个参数,并返回其值,同时ap指针向后移动,指向下一个参数。
参数:ap是一个已初始化的va_list变量;type是类型名,表示期望取出的参数的数据类型,如int、double等。
va_end
1  | void va_end(va_list ap);  | 
功能:结束对可变参数列表的遍历,并执行必要的清理工作。
参数:ap是需要清理的va_list变量。
说明:每一个va_start都必须与对应的va_end匹配,在调用完va_end后,ap就是未定义的了,无法直接再次使用。
va_copy
1  | void va_copy(va_list dest, va_list src);  | 
功能:拷贝src到dest中。
参数:dest是目标,作为src的副本;src是源,被拷贝。
说明:在需要多次遍历同一个可变参数列表时,可以先用va_copy创建一个副本。另外,使用va_copy初始化的va_list,最后也需要使用va_end进行清理。
test case
1  | 
  | 
在上述代码中,使用可变参数完成了两个简单的函数,这两个函数有一个很关键的共同点,那就是提供给这两个函数的第一个参数都是由用户传入的,而这个参数决定着被调函数何时执行结束。那么换句话说,使用可变参数实现的函数的结束时间,是由用户来掌控的,这样的行为也与库函数printf、scanf也是一致的。