可变参数列表

首先通过一个例子来了解可变列表参数
一个函数可以求出任意个参数的平均值:

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>

int average(int n,...)
{
	va_list arg;
	int i = 0;
	int sum = 0;
	va_start(arg, n);
	for(i = 0; i < n; i++)
	{
		sum = sum + va_arg(arg, int);
	}
	va_end(arg);
	return sum/n;
}

int main()
{
	int x = average(4, 1, 2, 3, 10);
	printf("%d", x);
	system("pause");
	return 0;
}

首先我们来分析一下这个函数,给函数传参时,你会发现,只有实参4被传给了n,而4之后的实参传过去都被...代替,这是什么意思呢?,其实第一个实参也就是4,代表的是在它之后实参的个数。而...代表的就是4之后的实参传过去的形参,这也是它为什么可以传任意个参数。

然后进入函数内部,这里可能有许多你不认识的代码,但是没关系,我们一句一句来分析。

第一个是  va_list arg;  我们看一下它的定义  


这里我们可以看出来va_list其实就是char*,这句代码的意思是声明一个char*类型的变量arg。

接下来的两句就是定义并初始化两个整形变量i和sum,

再下来的一句  va_start(arg, n);  可能又看不懂,但是没关系,我们转到定义


我们看到的是这个定义,但是_crt_va_start我们仍然不认识,当我们选中它再次转到定义是就是这样


这里我们可以看出va_start的作用,其中_ADDRESSOF()转到定义是取地址的意思,_INSIZEOF()的意思是当你要占用的最大的字节数,这里是整形所以_INSIZEOF()等于4,这句话替换之后就位 arg = (char*)&n+4,这句话什么意思呢,只有你学过栈帧(如下图所示),你就明白它代表的是第二个形参。其实va_start()的作用是将arg初始化。让arg指向你第一个要计算的形参。


接下来是一个for循环,va_arg的用法从上面的两张图可以看出,它可以替换为 *(int *)((arg = arg + 4)-4),其中(arg = arg + 4)的意思是指向下一个要计算的形参,但是为什么要-4呢,因为初始化时你已经指向了第二个形参,它是要进行计算的如果不-4回到原来的位置的话,就会漏掉第二个形参,使你的计算结果错误。最后将它强制类型转化为int型并解引用。

当它计算完之后 回来到va_end();他的意思从转到定义的图中可以看出,它的作用是将arg指针指向空。

可变参数的限制

1.可变参数必须从头到尾逐个访问,如果你想访问几个参数后版图停止也可以,但是如果你想一开始就访问中间的参数是不可以的.

2.参数列表中至少有一个命名参数,如果连一个命名参数都没有的话,就无法使用va_start,

3.这些宏是没有办法判断实际存在的参数的个数和类型。

4.一定要在va_arg中的括号里写入正确的类型,不然后果无法想象。




	

猜你喜欢

转载自blog.csdn.net/ksaila/article/details/80202723
今日推荐