C语言学习总结:可变参数列表的剖析

  在C语言中,我们一般经常使用的参数都是固定的,例如strcmp,strcpy,这些函数都只能有两个参数。但是在一些特殊的函数,例如printf,scanf中,他们的参数是可以改变的,这就是可变参数的使用。

  可变参数列表是通过宏实现的,宏定义在头文件stdarg中,这个头文件声明了一个类型va_list,三个宏va_start,va_arg,va_end.

  可变参数原型的声明格式:type VAFunction(type arg1,type arg2,...).参数分为两个部分:个数确定的固定参数和个数可变的可选参数。因为可选参数的个数是不确定的,所以用...来表示。

注意:函数至少有一个固定参数。

  我们先举个例子:

  实现一个函数可以求任意个参数的平均值

#include<stdio.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);
	}
	return sum/n;
	va_end(arg);
}

int main()
{
	int avg1 = average(3, 5, 6, 4);
	int avg2 = average(5, 1, 4, 6, 8, 11);
	printf("avg1 = %d\n",avg1);
	printf("avg2 = %d\n",avg2);
	return 0;
}

运行结果:

我们先转到定义看看它们是怎么实现的。

1.va_list arg

可以看出来,va_list其实就是char*,将char* 类型重命名为va_liat.

2.va_start(arg,n)

这个可能看着不太明白,那就继续转到定义。

我们再将不认识的字符转到定义。

现在看着就很明白了,我们将va_start这个宏替换一下。

arg = (va_list)&n+INTSIZEOF(n)

arg = (char*)&n+4

va_start(ap,v)就是把字符指针向后移动,跳过了第一个参数。

arg指向未知参数列表的第一个参数。

3.va_arg(arg,int)

现在,将va_arg这个宏替换一下。

*(int *)((arg = agr + 4) - 4)

这个表达式的作用是,arg=arg+4使arg指向下一个参数,再减去4,保留下来的就是上一个参数的地址。

4.va_end(arg)

将va_end替换一下,这个就比较简单。

arg = (char*)0

其实就是把va_end置成空指针,即va_end=NULL.

好了,我们现在总结一下:

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

· 这个变量是调用va_start来初始化的。它的第一个参数是va_list的变量名,第二个参数是省略号前最后一个有名字的参数。初始化过程把arg变量设置为指向可变参数部分的第一个参数。

· 为了访问参数,需要使用va_arg,这个宏接受两个参数:va_list变量和参数列表中下一个参数的类型。在这个例子中的所有可变参数都是整型。va_arg返回这个参数的值,并使用va_arg指向下一个可变参数。

· 最后,当访问完毕最后一个可变参数之后,我们需要调用va_end。

可变参数的限制

注意:

·  可变参数必须从头到尾逐个访问。不能半途而废,也不能从中间开始访问。

·  参数列表中至少有一个命名参数。若一个命名参数都没有,就无法使用va_start。

·  这些宏无法直接判断实际存在参数的数量。

·  这些宏无法判断每个参数的类型。

·  如果在va_arg中指定了错误的类型,那么其后果是不可预测的。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值