宏与可变参数

    对于打印函数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 ",avg);

}

    以上实例就是求几个数的平均值,但给出的数字可以不限个数,究其整个实现过程,主要是由va_listva_startva_argva_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即平均数。

这些源代码虽然难,但是看懂这些对于能力的提升还是很有帮助的。

原文地址:https://www.cnblogs.com/qingjiaowoxiaoxioashou/p/5689920.html