目录
简介
之前在查阅资料时一直没有找到一个完整的介绍这些宏的文章,故根据自己的理解整理了一下。va_list ,va_start ,va_arg ,va_end是C中stdarg.h头文件里面的宏,它们主要用于配合处理一组可变参数,这组可变参数的数量无需提前确定,用起来十分灵活。
typedef char *va_list;
va_start宏
va_start(list, param1) list: va_list类型的指针 param1: 最后一个固定参数(若有多个固定参数)
#define va_start(list,param1) ( list = (va_list)¶m1+ sizeof(param1) )
看它在定义的时候,list = (va_list)¶m1+ sizeof(param1),其中的list本来是va_list类型指针,param1是最后一个固定参数的地址,经过这步操作后将list成功指向了第一个可变参数。 如图:
va_arg宏
弄懂这个宏不难 va_arg(list, mode) list: va_list类型的变量 mode: 要返回的参数类型 返回值:返回当前指针指向的可变参数(第一次为第一个可变参数) 经过多次验证,如果使用这个宏可变参数列表中类型必须相同,因为mode的参数类型不可变,返回后将指针指向下一个参数
#define va_arg(list,mode) ( (mode *) ( list += sizeof(mode) ) )[-1]
观察这个宏定义就明白了,在执行va_start这个宏后就已经将指针指向了第一个可变参数,这时执行list += sizeof(mode)就会将指针指向下一个可变参数。 如图:
va_end宏
va_end(list) list: va_list类型的变量 执行该宏可以清空可变参数列表
实例:利用va_arg打印
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
void var_test(char *format, ...)
{
va_list list;
va_start(list,format);
char *ch;
while(1)
{
ch = va_arg(list, char *);
if(strcmp(ch,"") == 0)
{
printf("\n");
break;
}
printf("%s ",ch);
}
va_end(list);
}
int main()
{
var_test("test","this","is","a","test","");
return 0;
}
这里用了va_arg宏,第一个可变参数为“this”,所以从“this”开始打印,可变参数类型也相同。
实例:打印不同可变参数类型
那么如何打印不同的可变参数类型呢,需要用到vprintf。
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
int myprintf(char *format, ...)
{
va_list ap;
int n;
va_start(ap, format);
n = vprintf(format, ap);
va_end(ap);
return n;
}
int main()
{
int n = myprintf("%s %s %d %s %s\n","I","am",22,"years","old");
printf("%d",n);
return 0;
}
在这个历程中,实现了不同类型输出,但没有使用va_arg这个宏,因为这个宏里面mode参数的类型不可变,所以不能用va_arg来控制指针偏移,如果想利用va_list来输出不同类型的参数时,需要如此做。