C语言实现可变函数参数

可变函数参数复习

首先,来看一个可变参数函数:

#include <stdio.h>
#include <stdarg.h>
int Max(int n,...);//可变参数函数,求最大值 
int main(int argc,char *argv[])
{
	int max=Max(5,2,1,6,3,5) ;
	printf("%d\n",max);
	return 0;
}

int Max(int n,...)
{
	int i=0,max=0,num=0;
	va_list arg;         //与 cahr *arg;等价
	va_start(arg,n);     //arg指向第一个可变参数 2
	max=va_arg(arg,int);
	for(i=0;i<n;i++)
	{
		num=va_arg(arg,int);
		if(max<num)
		{
			max=num;
		}
	}
	va_end(arg);        //arg=NULL;
	return max;
}

这个函数很简单,就是求最大值。特点就是可以输入任意个参数,而没有像以往的函数一样固定参数个数。
查看代码,我们发现几个没见过的东东:
va_list
va_start
va_arg
va_end
"…"符号

声明一下,这些都不是函数,而是宏定义
va–variable argument(可变的参数)

(1)va_list
查看stdarg.h文件
typedf char* va_list;
所以,va_list其实是一个指向char类型的指针。
(2)va_start()
查看stdarg.h文件

#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

再次强调,这是宏,宏,宏!不是函数!
看到有点头大吧!来,分析分析:
首先:

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

[推荐答案]
_INTSIZEOF(n)整个做的事情就是将n的长度化为int长度的整数倍。
比如n为5,二进制就是101b,int长度为4,二进制为100b,那么n化为int长度的整数倍就应该为8。
~(sizeof(int) - 1) )就应该为(4-1)=(00000011b)=11111100b,这样任何数& ~(sizeof(int) - 1) )后最后两位肯定为0,就肯定是4的整数倍了。
(sizeof(n) + sizeof(int) - 1)就是将大于4m但小于等于4(m+1)的数提高到大于等于4(m+1)但小于4(m+2),这样再& ~(sizeof(int) - 1) )后就正好将原长度补齐到4的倍数了。

原文地址:

http://blog.csdn.net/sdcxyz/article/details/7067699

我们知道对于IX86,sizeof(int)一定是4的整数倍,所以~(sizeof(int) - 1) )的值一定是 右面[sizeof(n)-1]/2位为0,整个这个宏也就是保证了右面[sizeof(n)-1]/2位为0,其余位置
为1,所以_INTSIZEOF(n)的值只有可能是4,8,16,…等等,实际上是实现了字节对齐。

_INTSIZEOF(n) 的目的在于把sizeof(n)的结果变成至少是sizeof(int)的整倍数,这个一般用来在结构中实现按int的倍数对齐
如果sizeof(int)是4,那么,当sizeof(n)的结果在14之间是,_INTSIZEOF(n)的结果会是4;当sizeof(n)的结果在58时,
_INTSIZEOF(n)的结果会是8;当sizeof(n)的结果在9~12时,_INTSIZEOF(n)的结果会是12;……总之,会是sizeof(int)的倍数。

走远了,再回来讲va_start():

#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

ap是类型为va_list的指针,v是可变参数最左边的参数,亦即最后一个固定参数。
运行完这句代码后,ap指向第一个可变参数在堆栈中的地址。
|------------------------------------------------|高地址
|-------------函数返回地址------------------|
|------------…-----------------|
|------------------------------------------------|<–va_arg后ap指向下一个参数
|----- 第n个参数(第一个可变参数)-----|
|------------------------------------------------|<–va_start后ap指向第一个可变参数
|— 第n-1个参数(最后一个固定参数)----|
|------------------------------------------------|<–&v 低地址

所以,va_start(arg,n);运行后,arg指向了第一个可变参数“2”。
(3)va_arg(arg,int)

#define va_arg(ap,t)  (*(t*)((ap+=_INTSIZEOF(t))- 		           _INTSIZEOF(t))) 

va_arg()取可变参数的值。

代码精髓:
*( t )((ap+=_INTSIZEOF( t ) ) - _INTSIZEOF(t))
首先,ap += sizeof( t ),ap已经指向下一个参数的地址了(ap的值改变);
然后,ap-sizeof( t ),又返回前一个参数了(ap的值没有改变),用
取出参数的值。

一句代码,其实执行了两步,妙哉妙哉!

(4)va_end(arg)

#define va_end(ap)      ( ap = (va_list)0 )

使ap不再指向堆栈,而是跟NULL一样。

OK,关于可变函数参数就到这了!
思考:printf()怎么实现的呢!写出自己的myprintf()函数吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值