浅析可变参数列表

一般的函数在传参时只能传一个或两个甚至多个参数,但其前提是参数的个数必须是固定不变的。printf()函数和scanf()函数的参数却是可变的。在printf()函数中,它所传的参数是由标准化格式输出的类型决定。
例:
int main()
{
    printf("%s\n", "hello world");
    printf("%s%s%c", "hello ", "worl", 'd');
    system("pause");
    return 0;
}
这段代码中,第一个printf有一个%s代表其参数只有一个,而第二个有三个分别是%s%s%c则代表有三个参数。两者结果相同。

这里写图片描述
对于scanf与printf相类似。
而对一般的函数要如何来做到这一点呢?下面我就来简单介绍一下可变参数列表来实现这一功能。

int average(int n, ...)
{
    va_list arg;
    //typedef char *  va_list;
    int i = 0;
    int sum = 0;
    va_start(arg, n);
    //#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
    for (i = 0; i < n; i++)
    {
        sum += va_arg(arg, int);
        //#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
    }
    return sum / n;
    va_end(arg);
    //#define _crt_va_end(ap)      ( ap = (va_list)0 )
}
int main()
{
    int a = 1;
    int b = 2;
    int c = 3;
    int avg1 = average(2, a, c);
    int avg2 = average(3, a, b, c);
    printf("avg1 = %d\n", avg1);
    printf("avg2 = %d\n", avg2);
    system("pause");
    return 0;
}
这段代码是用来求几个数的平均值。main函数中的这两句
int avg1 = average(2, a, c);
int avg2 = average(3, a, b, c);
中的2,3都是为后面函数在栈帧中寻找提供起始地址和控制循环次数。
而average函数中:
va_list arg;
//typedef char *  va_list;表示arg是一个char型的指针,arg里面存的是一个地址。
va_start(arg, n);
//#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) );这段则表示将arg的地址赋值为位置参数列表中第一个未知参数。在函数栈帧中如图

这里写图片描述
其中intsizeof()函数的意思是向上取整。
va_arg(arg, int);
//#define _crt_va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) );即((int )((arg+=_INTSIZEOF(int))-_INTSIZEOF(int)))此时arg是一个int型指针,指向第二个未知参数,而表达式取的值是第一个未知参数的值。在函数栈帧中这样表示:
这里写图片描述
va_end(arg);
//#define _crt_va_end(ap) ( ap = (va_list)0 )
循环结束后给arg赋空指针。
在运用可变参数列表时,需要注意传n和传类型!va_arg这个表达式执行一次后就会指向下一个变量,不再是当前变量,在使用时需谨慎!可变参数列表在使用是只能从第一个挨个取直到最后一个,中间不能跳过几个变量!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值