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
也是一致的。