可变参数列表是通过宏来实现的,这些宏定义在stdarg.h头文件,它是标准库的一部分。
这个头文件声明了一个类型va_list和三个宏:va_start、va_arg和va_end。
typedef char *va_list;
#define va_start(ap, A) (void)((ap) = (char *)&(A) + _Bnd(A, _AUPBND)) //第一个参数是va_list类型的变量,第二个参数是省略号前最后一个有名字的参数,功能是初始化va_list类型的变量,将其值设置为可变参数的第一个变量。
#define va_arg(ap, T) (*(T )((ap) += _Bnd(T, _AUPBND)) - _Bnd(T, _ADNBND))) //第一个参数是va_list类型的变量,第二个参数是参数列表的下一个参数的类型。va_arg返回va_list变量的值,并使该变量指向下一个可变参数。
#define va_end(ap) (void)0 //在va_arg访问完最后一个可变参数之后调用的。从功能上可以不要
使用示例:
1、求int型平均值
int CalcAvergeVal(int cnt, ...)
{
va_list arg;
int idx;
int sum = 0;
va_start(arg, cnt);
for (idx = 0; idx < cnt; idx++)
{
sum += va_arg(arg, int);
}
va_end(arg);
if (cnt > 0)
{
return sum / cnt;
}
else
{
return 0;
}
}
2、实现printf函数
int my_printf(const char *format, ...)
{
va_list arg;
va_start(arg, format);
while (*format != '\0')
{
if ('%' == *format)
{
char ch;
char arr[10];
char *p;
int x;
switch (*(format + 1))
{
case 'c':
ch = va_arg(arg, char);
putc(ch, stdout);
case 'd':
x = va_arg(arg, int);
p = arr;
_itoa_s(x, p, 10, 10);
while(*p != '\0') putc(*p++, stdout);
default:
break;
}
format += 2;
}
else
{
putc(*format++, stdout);
}
}
va_end(arg);
return 0;
}