第一次接触这个词的时候还是通过printf了解的,今天还用这个作为例来描述。
说到可变参数列表,不得不提到stdarg宏。可变参数列表是通过宏实现的,而这些宏就定义在 stdarg.h头文件。说到这个头文件,就得细说一下,毕竟第一次见到嘛!这个头文件中声明了一个类型(va_list)和三个宏(va_start)(va_arg)(va_end)。使用时一般是声明一个类型为va_list的变量和这三个宏配合使用,访问参数的值。
下面说一下一个问题:模拟实现printf
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void print(char * val, ...) //可变参数列表
{
char *c = NULL;
va_list arg; //声明一个 va_list 类型的变量
va_start(arg, val); //准备访问可变参数列表
while (*val != '\0') { /val指向"val:s ccc"
if (*val == 's') {
puts(va_arg(arg, char*));
}
else if (*val == 'c') {
putchar(va_arg(arg, char));
}
else
putchar(*val);
++val;
}
va_end(arg); //完成处理可变参数
}
int main()
{
print("val:s ccc", "hello", 'b', 'i', 't');
system("pause");
return 0;
}
针对va_arg这个宏,在这里细说一下:
其基本类型为:type va_arg(va_list ap, type);
这里参数ap应该首先被宏va_start 或 va_copy初始化,但又必须在被宏va_end调用之前使用。每次调用va_arg都会改变ap值使得后续的参数值能被依次添加。参数type应该是一个类型名,并且用type*能够得到该类型的指针类型。如果type为空,或者type和实际参数不匹配, 那么除了以下两种情况,这个宏的行为是未定义的。
一个是带符号整型,另一个是与之对应的无符号整型,并且值可以被表达成这两种类型的任何一种;
一个是空类型指针,另一个是字符类型指针。
返回值:第一次调用va_arg返回parmN之后的参数值,后续的调用依次返回剩下的参数值。parmN应为函数中“…”前最后一个参数值。