可不参数列表可以让函数在不同时候接受不同数目的参数。
C语言可变参数列表使用总可分为4个部分.
1、va_list
首先,我们先来看一下它的定义:
#ifdef _M_ALPHA
typedef struct{
char*a0;/*pointertofirsthomedintegerargument*/
intoffset;/*byteoffsetofnextparameter*/
}va_list;
#else
typedef char*va_list;#endif
就我们所知,typedef将va_list定义成了一个char*类型;
所以在使用va_list时,
va_list arg;//作用就是将arg定义成了一个char类型的指针
2、va_start
va_start是一个宏,它的作用是获取第一个参数的地址,即括号内的最左边第一个参数
的地址。
它的定义为:
#defineva_start(ap,v)(ap=(va_list)&v+_INTSIZEOF(v))
使ap指向第一个参数的地址。(ap即为va_list所定义的指针)
这里使用到了一个_INTSIZEOF,注意,它也是一个宏,作用是获取目标参数v所占用空间的
长度大小。
它在这里起到了一个初始化的作用。具体的使用在下面会举例。
3、va_arg
va_arg是一个宏,它的作用是向后访问。定义为:
#defineva_arg(ap,t)(*(t*)((ap+=_INTSIZEOF(t))-_INTSIZEOF(t)))
每次调用,它先获取当前的参数,并使指针ap指向下一个参数。
(至于这里为什么先使ap加上一个_INTSIZEOF(t), 又减去一个_INTSIZEOF(t)。从而起到是ap
指针向后移动的作用,博主尚未弄明白)。
4、va_end
类型也是宏,作用为清空 va_list所定义的可变参数列表。
#define va_end(ap) (ap=(va_list)0)
5、可变参数列表有几个限制条件
<1> 函数的参数至少含有一个。
<2> va_start无法计算参数的个数。
<3> 无法直接知道参数类型。
<4> va_arg如果给定了错误的类型,结果不可预料。
下面来看一个例子
// 利用可变参数列表模拟printf函数输出字符串,字符。
#include<stdio.h>
#include<stdarg.h>
void print(const char *format,...)
{
va_list arg;
//定义arg(char类型)指针
va_start(arg,format);
//对arg进行初始化,使其指向第一个参数
while(*format)
{
switch(*format)
//因为有字符,字符串两种情况,所以这里用switch比较好。
{
case's':
//若读取到为s,则为字符串
{
char *str=va_arg(arg,char*);
/*注意,这里要用一个局部变量对va_arg(arg,char*)进行一次保存,
因为每次调用一次va_arg(arg,char*),它都会向后移动, 若,直接
puts(va_arg(arg,char*))会输出下一个参数的值。*/
puts(str);
}
break;
case'c':
//若为猜,则为字符。
{
char tmp=va_arg(arg,char);//若此处char不行,换用int 试一下。博主遇到过这种情况,尚未明白。
//同样用tmp进行一次保存。
/*注意,va_arg不会辨别参数的类型,该参数是什么类型,va_arg括号中
第二个位置就写什么类型,不要写错,不热会造成不可预料的后果。这也是
可变参数列表的一个限制条件。*/
putchar(tmp);
}
break;
default:
/*当switch所有情况列举完后,用default分支结尾。即使真的不需要default,
也应该保留语句 ,具体作用自己网查*/
putchar(*format);
break;
}
format++;
}
va_end(arg);//最后清空va_list定义的arg
}
int main()
{
print("s ccc.\n","hello",'b','i','t');
return 0;
}
执行后结果应为: