• 宏与可变参数


        对于打印函数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即平均数。

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

  • 相关阅读:
    2020/2/14
    2020/2/13
    《人类简史》
    2020/2/12
    bzoj3157国王奇遇记(秦九韶算法+矩乘)&&bzoj233AC达成
    [noip科普]关于LIS和一类可以用树状数组优化的DP
    [uva11722&&cogs1488]和朋友会面Joining with Friend
    Bzoj2154 Crash的数字表格 乘法逆元+莫比乌斯反演(TLE)
    NOIP2016滚粗记
    bzoj2228[ZJOI2011]礼物(gift)
  • 原文地址:https://www.cnblogs.com/qingjiaowoxiaoxioashou/p/5689920.html
Copyright © 2020-2023  润新知