可变参数列表的使用是很有必要的一件事情,在实现某个功能时,你可能不知道传几个参数。下面简单介绍一下可变参数列表的使用。
可变参数列表是通过宏来实现的,定义与stdarg.h头文件中。
void va_start(va_list ap, last); //va_start用来初始化参数列表t
type va_arg(va_list ap, type); //va_arg用来获取参数列表中的一个参数,类型为type。
void va_end(va_list ap); //va_end用来清理参数列表。
void va_copy(va_list dest, va_list src); //va_copy用来拷贝参数列表
下面是这些函数宏的实现
typedef char * va_list; //字符串指针
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1)& ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
下面是宏的具体作用
va_list
typedef char * va_list;
/*宏的定义
把char*重命名为va_list,使得va_list定义的指针变量可以访问到未知参数列表*/
va_start
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
/*初始化参数列表
_INTSIZEOF(v)的作用是跳过最后一个已知变量v,ap取到未知参数列表的第一个参数,完成参数列表的初始化*/
va_arg
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
/*取出当前参数
t是未知参数列表中参数的类型。
((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))的作用是使得每次调用va_arg都能使指针自动往后移动一位,本次对本参数访问的同时,下次可以访问到下一个参数。/
va_end
#define va_end(ap) ( ap = (va_list)0 )
/*清空参数列表
把指向参数列表的指针置为0,达到清理参数列表的目的*/
接下来具体介绍可变参数列表的使用
1.求n 个数的平均数
#include<stdarg.h>
#include<stdio.h>
int Average(int n,...)
{
int i = 0;
int sum = 0;
va_list arg;
//char* arg 类型重命名
va_start(arg, n);
// #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 宏的实现
// 替换后 ( arg = (char*)&n + 4 )
for (i = 0; i < n; i++)
{
sum += va_arg(arg, int);
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 宏的实现
//替换后 sum += ( *(int*)((arg += 4) - 4))
}
va_end(arg);
//#define va_end(ap) ( ap = (va_list)0 )
//替换后 (arg = (char*)0 );
return sum / n;
}
int main()
{
int ave = Average(3, 1, 2, 3);
printf("ave = %d\n", ave);
system("pause");
return 0;
}
2.求取参数部分n个里面的最大值
#include<stdarg.h>
#include<stdio.h>
int Max(int n, ...)
{
int i = 0;
va_list arg;
va_start(arg, n);
int tmp = va_arg(arg, int); //tmp 用来保存第一个数 即-3
for (i = 0; i < n-1; i++)
{
int tmp1 = va_arg(arg, int); // 此时 tmp1 用来保存后面的数 ,即循环一次访问一个接下来元素
if (tmp < tmp1)
{
tmp = tmp1;
}
}
return tmp;
}
int main()
{
int max = Max(3, -3, -1, -2);
printf("max = %d\n", max);
system("pause");
return 0;
}
3.printf函数的模拟实现
#include<stdarg.h>
#include<stdio.h>
#include<assert.h>
void display(int n)
{
if (n > 9)
{
display(n / 10);
}
putchar(n % 10 + '0');
}
void print(char *format, ...)
{
assert(format != NULL);
va_list arg;
va_start(arg, format);
while (*format)
{
switch (*format)
{
case 's':
{
char *ret = va_arg(arg, char*);
while (*ret)
{
putchar(*ret);
ret++;
}
}
break;
case 'c':
{
char ret = va_arg(arg, char);
putchar(ret);
}
break;
case 'd':
display(va_arg(arg, int));
break;
default:
putchar(*format);
break;
}
format++;
}
}
int main()
{
print("s ccc d.\n", "hello", 'B', 'A', 'T', 100);
system("pause");
return 0;
}
以上就是我对可变参数列表的一些理解,有不对的地方还希望指正。