标签:
对于打印函数printf我们太熟悉不过,但真是这样吗?看看其原型:
int printf( const char *format [, argument]... );
等等,末尾的…是什么意思?省略号?是想留给读者无限的遐想空间?你大可这样认为,因为这是不固定参数,简称不定参数,换句话说,有多少参数都行,只要你敢想。
我们想看看可变参数如何使用,并且怎样实现可变参数。先看下面的例子:
#include<stdio.h>
#include<malloc.h>
#include<stdarg.h>
int Avg(int n, ... )
{
int sum = 0;
va_list var_arg;
va_start(var_arg, n);
for(int i=0; i<n; ++i)
{
sum += va_arg(var_arg,int);
}
va_end(var_arg);
return sum / n;
}
void main()
{
int avg = Avg(4,10,20,30,40);
printf("avg = %d\n",avg);
}
以上实例就是求几个数的平均值,但给出的数字可以不限个数,究其整个实现过程,主要是由va_list、va_start、va_arg、va_end来完成,那这些看似函数的东西是什么了,实际上就是宏。
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
以上的宏都代表什么含义呢?
实际上va_list就代表了char *,
va_list var_arg;
就相当于char *var_arg;
va_start(var_arg,n);就相当于调动了上面的宏#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ),代表了宏所定义的表达式。
在这个宏中又调用了另外一个宏: #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
首先我们可以把宏解析成如这样的式子(默认为32位系统下):(sizeof(n)+4-1)&~(4-1)--->(sizeof(n)+3)&~3)
3的二进制可写为0000 0011,取反之后为1111 1100,我们发现sizeof(n)+3&~3都被提升为4的倍数,我们再反过来看上面的宏#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
分析的步骤跟上面的是一样的,首先把他展开来:ap=(char*)&v+_INTSIZEOF(v); ap就相当于加上了一个整型空间,指向了真实数据的存储位置。
接下来循环开始,每次取一个值加到sum上,直到所有数字加完。va_arg这个宏就相当于在空间中把一个一个的值取出来。
#define va_end(ap) ( ap = (va_list)0 );最后一个end指针相当于把字符指针赋为空值,最后返回sum/n即平均数。
这些源代码虽然难,但是看懂这些对于能力的提升还是很有帮助的。
标签:
原文地址:http://www.cnblogs.com/qingjiaowoxiaoxioashou/p/5689920.html