可变参数列表

有时,我们需要实现一个函数并希望这个函数可以传递可变数量的参数,就需要用到可变参数。它允许定义一个函数,能根据需求具体接受可变数量的参数。如下:

int fun(int n, ...)
{
    //...
}
int main()
{
    fun(2,3,4);
    fun(4,1,2,5,6);
    return 0;
}

fun()函数中的...代表可变参数,省略号前的int n代表要传递的可变参数的个数。


C语言中可以将函数实现为可变参数的形式,从而达到接受1个以上的任意多个参数的目的。
先来看一个例子:
实现一个函数可以求任意个参数的平均值。

#include <stdio.h>
#include <stdarg.h>
int average(int n, ...)
{
    va_list arg;
    int sum = 0;
    int i = 0;
    va_start(arg, n);
    for(i=0; i<n; i++)
    {
        sum += va_arg(arg, int);
    }
    va_end(arg);
    return sum/n;
}
int main()
{
    int ret = 0;
    ret = average(5,1,2,3,4,5);
    printf("%d\n",ret);
    return 0;
}

首先我们来明确一下上面出现的va_listva_startva_argva_end都是起什么作用的:

  • va_list的汇编代码中就是char *
typedef char *  va_list;

简单来说就是声明一个va_list类型的变量arg,它用于访问参数列表的未确定部分。


  • va_start的汇编代码中如下:
#define va_start _crt_va_start

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

宏定义中_ADDRESSOF(v)就是&v_INTSIZEOF(v)在本例中是4,va_listchar *;所以va_start的作用是初始化arg为指向未知参数列表第一个参数的地址。它的第一个参数是va_list的变量名,第二个参数是省略号前最后一个有名字的参数。


  • va_arg

为了访问参数,需要使用va_arg,它的汇编代码为:

#define va_arg _crt_va_arg

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

宏定义中的( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )在本例中可等价为
( *(int *)((arg += 4) - 4) ),这个宏接受两个参数:va_list变量和参数列表中下一个参数的类型,本例中所有的可变参数都是整型。
va_arg返回这个参数的值,并使va_arg指向下一个可变参数。


  • va_end

当访问完毕最后一个可变参数之后,需要调用va_end,它的汇编代码如下:

#define va_end _crt_va_end

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

va_end就是把arg置为空指针。


注意:

  • 可变参数必须从头到尾逐个访问。(如果你访问了几个可变参数后不想访问了,这样是可以的;但要是从一想开始就访问列表中间的参数不不可以的)

  • 参数列表中至少有一个命名参数。(如果连一个命名参数都没有,就无法使用va_start

  • 这些宏是无法直接判断实际存在参数的数量。

  • 这些宏无法判断每个参数的类型。

  • 不要在va_arg中指定了错误的类型,否则结果不可预测。

  • 使用可变参数需要引用头文件#include <stdarg.h>


最后来一道题再练习一下可变参数:
使用可变参数,实现函数,求函数参数的最大值。

#include <stdio.h>
#include <stdarg.h>

int max(int n, ...)
{
    va_list arg;
    int max = 0;
    int i = 0;
    va_start(arg, n);
    for(i=1; i<n; i++)
    {
        int tmp = 0;
        if((tmp = va_arg(arg, int))>max)
            max = tmp;
    }
    return max;
}

int main()
{
    int ret = 0;
    ret = max(5, 1, 2, 6, 3, 4);
    printf("%d\n",ret);
    return 0;
}

END

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值