可变参数
函数可以接受1个以上的任意多个参数(不固定)
先看一个例子
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
int avergae(int n, ...)//...表示参数是未知的
{
va_list arg;//字符指针 typedef char* va_list;
int i = 0;
int sum = 0;
va_start(arg, n);//把上面获得的字符指针,向后移动四个字节,跳过 n 的内存地址
for (i = 0; i < n; i++)
{
sum = sum + va_arg(arg, int);//arg向后移动四个字节(sizeof(int)大小)
}
return sum / n;
va_end(arg);//结束标志
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int avg1 = avergae(3, a, b, c);
printf("平均数=%d\n", avg1);
system("pause");
return 0;
}
上述代码中
1.声明了一个va_list类型的变量arg,arg相当于一个指针,用来访问参数列表未知的部分。
2.指针arg是利用va_start来初始化的,使arg指向参数列表中的未知参数的第一个。
3.va_arg是用来访问参数列表中所有的未知参数的宏,该va_arg有两个参数,arg变量和所要访问的下一个未知参数的类型。va_arg返回这个未知参数的值,并且使arg指向下一个未知参数。
4.当访问完所有的未知参数是,调用va_end使变量arg为空指针。
1.声明了一个va_list类型的变量arg,arg相当于一个指针,用来访问参数列表未知的部分。
2.指针arg是利用va_start来初始化的,使arg指向参数列表中的未知参数的第一个。
3.va_arg是用来访问参数列表中所有的未知参数的宏,该va_arg有两个参数,arg变量和所要访问的下一个未知参数的类型。va_arg返回这个未知参数的值,并且使arg指向下一个未知参数。
4.当访问完所有的未知参数是,调用va_end使变量arg为空指针。
可变参数列表
va_list arg; 转到定义
:typedef char* va_list; 重命名char* 为va_list。此处va_list就相当于 char*了,可以定义指针。
va_arg(arg, int); 转到定义:
#define va_arg __crt_va_arg,__crt_va_arg。
转到定义: #define __crt_va_arg(ap, t) ((t)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 。
ap表示可变参数指针,而t表示数据类型。
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
转到定义: #define __crt_va_arg(ap, t) ((t)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 。
ap表示可变参数指针,而t表示数据类型。
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
(sizeof(int)-1),该表达式结果是3,当参数t为char时,’&’前面的表达式结果取最小值4,因此,两边表达式运算结果是4。
(*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))。该表达式先让指针ap加上4字节的大小,再把减去4字节大小处所对应的值返回。用t强制类型转换,再解引用。注意此处t是传入参数的数据类型。
va_end(arg); 转到定义:
#define va_end __crt_va_end,继续转到定义
:#define __crt_va_end(ap) ((void)(ap = (va_list)0)),由此看出,该语句把整型0强制转换为字符0, 然后传给指针ap,由此可知将ap清空。
可变参数限制
1.可变参数必须从头到尾的访问,可以半途停止,但不允许直接访问中间参数,
2. 参数必须要有一个命名参数;
3. 这些宏不能直接判断实际存在参数的数量,也无法判断每个参数的类型;