可变参数函数

在看代码的时候时不时会看到#define PRINTF(arg...)  printf(arg)类此这样的语句。

这里的这个(arg...)就是可变参数,拥有这样参数的函数就叫做可变参数函数。也叫做VA函数(variable argument function)。

可变参数函数,故名思议就是参数的数量不定,可以变化。

举个例子先:

printf函数是一个典型的参数可变的函数。在保证它的第一个参数是字符串的条件下,你可以输任意数量任意合法类型的参数。只要你在第一个字符串参数中使用了对应的格式化字符串,你就可以输出正确的值。这难道不是件很有趣的事吗?那它是怎么做到的?

1,首先,怎么得到参数的值。对于一般的函数,我们可以通过参数对应在参数列表里的标识符来得到。但是参数可变函数那些可变的参数是没有参数标识符的,它只有“…”,所以通过标识符来得到是不可能的,我们只有另辟途径。

我们知道函数调用时都会分配栈空间,而函数调用机制中的栈结构如下图所示:

                       |     ......     |

                       ------------------

                       |     参数2      |

                       ------------------

                       |     参数1      |

                       ------------------

                       |    返回地址    |

                       ------------------

                       |调用函数运行状态|

                       ------------------

可见,参数是连续存储在栈里面的,那么也就是说,我们只要得到可变参数的前一个参数的地址,就可以通过指针访问到那些可变参数。但是怎么样得到可变参数的前一个参数的地址呢?不知道你注意到没有,参数可变函数在可变参数之前必有一个参数是固定的,并使用标识符,而且通常被声明为char*类型,printf函数也不例外。这样的话,我们就可以通过这个参数对应的标识符来得到地址,从而访问其他参数变得可能。我们可以写一个测试程序来试一下:

#include <stdio.h>

void va_test(char* fmt,...);//参数可变的函数声明

void main()

{

    int a=1,c=55;

       char b='b';

    va_test("",a,b,c);//用四个参数做测试

}

void va_test(char* fmt,...) //参数可变的函数定义,注意第一个参数为char* fmt

{

   char *p=NULL;

      p=(char *)&fmt;//注意不是指向fmt,而是指向&fmt,并且强制转化为char *,以便一个一个字节访问

      for(int i = 0;i<16;i++)//16是通过计算的值(参数个数*4个字节),只是为了测试,暂且将就一下

      {

                printf("%.4d ",*p);//输出p指针指向地址的值

        p++;

      }

}

编译运行的结果为

  0056 0000 0066 0000 | 0001 0000 0000 0000 | 0098 0000 0000 0000 | 0055 0000 0000 0000

由运行结果可见,通过这样方式可以逐一获得可变参数的值。

2,怎样确定参数类型和数量

通过上述的方式,我们首先解决了取得可变参数值的问题,但是对于一个参数,值很重要,其类型同样举足轻重,而对于一个函数来讲参数个数也非常重要,否则就会产生了一系列的麻烦来。通过访问存储参数的栈空间,我们并不能得到关于类型的任何信息和参数个数的任何信息。我想你应该想到了——使用char *参数。Printf函数就是这样实现的,它把后面的可变参数类型都放到了char *指向的字符数组里,并通过%来标识以便与其它的字符相区别,从而确定了参数类型也确定了参数个数。其实,用何种方式来到达这样的效果取决于函数的实现。比如说,定义一个函数,预知它的可变参数类型都是int,那么固定参数完全可以用int类型来替换char*类型,因为只要得到参数个数就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值