C语言-----可变参数解析

写在开头:

     当我们想实现的函数功能的参数不确定时,我们就不能用同一个函数去实现不同参数的传递,此时,我们可以将函数实现成为可变参数的形式,可以使函数接受一个以上任意参数的传递。

举个栗子:

int main()
{
	int ave = 0;
	ave = average(2, 2,2);
	printf("%d\n", ave);
	ave = average(3, 2,2,2);
	printf("%d\n", ave);
	system("pause");
	return 0;
}

当我们要求平均数的时,需要调用两次average函数,第一次有四个参数,第二次有三个参数,这时可以用可变参数的形式来进行函数实现。
可变参数的形式:
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);
	}
	return sum / n;
	va_end(arg);
}

现在来解释一下这段代码的含义(在vc下查看比较直观),因为这个编译器比较久了,封装的比较简单,易于查看。我们先来了解几个在代码中出现的不熟悉的地方。
代码解释:

选择va_list右击转到定义,可以看到  typedef char *  va_list;类型重命名va_list给char*,则可以替换掉。

选择va_start同样右击转到定义查看,是一个宏定义
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

我们可以替换掉( arg = (char *)&n + _INTSIZEOF(n) );其中_INTSIZEOF(n)这也是一条宏定义,其含义为取4的整数倍,比如当n1,2,3,4,时,这个值取4;为5,6,7,8时就取8.整条语句可以替换为 arg=(char*)&n+4  arg 来到了未知参数部分的第一个参数,找到了起始位置。


选中va_arg右击转到定义,也是一个宏定义
#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )替换为 ( *(int *)((arg += 4) - 4 ),arg向后跳四个字节即int的字节数,指向第二个参数位置,然后-4还是第一个参数的值,但agr已经指向第二个位置了

选中va_end转到定义查看,#define va_end(ap) ( ap = (va_list)0 )替换为(arg=(va_list)0);
使用宏替换之后的代码如下图:
#include <stdarg.h>
#include <stdio.h>

int average(int n, ...)
{
	//va_list arg;
	char *arg;
	int i=0;
	int sum=0;
	//va_start(arg, n); 
	//#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
	//#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
	( arg = (char *)&n +4 ); // _INTSIZEOF(n)=4,
	for (i = 0; i < n; i++)
	{
		//sum = sum + va_arg(arg, int);
		sum +=( *(int *)((arg += 4) - 4 ));//arg向后跳四个字节即int的字节数,指向第二个参数位置,然后-4还是第一个参数的值,但agr已经指向第二个位置了
	}
	//va_end(arg);
	(arg=(char*)0);//赋成空指针
	return sum / n;
}
int main()
{
	int ave = 0;
	ave = average(2, 2,2);
	printf("%d\n", ave);
	ave = average(3, 2,2,2);
	printf("%d\n", ave);
	return 0;
}

总结:

※  声明一个va_list类型的变量arg,它用于访问访问参数列表的未知部分。

调用va_start来对arg进行初始化,它的第一个参数是va_list的变量名arg,第二个参数是省略号前最后一个有名字的参数。初始化过程中arg变量设置为指向可变参数部分的第一个参数。
访问参数需要使用va_arg,这个宏接受两个参数:va_list变量和参数列表中下一个参数类型。在这个例子中,所有可变参数都是整型。va_arg返回这个参数的值,并指向下一个可变参数。
※  最后,访问完最后一个可变参数时,需要使用va_end


猜你喜欢

转载自blog.csdn.net/abc_xixi111/article/details/79999604