C++中函数的可变参数列表

1.缺省参数实现参数列表可变(差的方案)

当我们在写一个参数个数未知而类型确定的函数(如计算多个整型数字的平均数)时,可以用函数的第一个参数表示后面的参数个数,并定义多个缺省参数,在函数体内读取相应个数的参数。

#include <iostream>
using namespace std;
float average(int number, int a, int b = 0, int c = 0, int d = 0, int e = 0)
{
    float sum = a + b + c + d + e;  //求出总和
    return sum / number;
}
int main()
{
    float aver = average(3, 1, 5, 4);
    cout << aver << endl;
    return 0;
}

当然,用一个数组来存储数据并作为参数可以更加省事,但这只是个例子,为了引出今天的主角。

请主角出场之前,我们先来分析一下上面的方案的缺点。首先,它无法的参数的数量进行检测,无法检测到参数过多的情况;其次,上述函数只能计算不超过5个整型数字的平均值。而且,当average函数中b,c,d,e没有以缺省参数的形式定义的时候,主函数中的调用行为是未定义的。这样,average函数的第一个参数可能与number对应,也可能与a对应。

2.stdarg宏

首先声明一个函数(以求平均数的函数为样例,以便和缺省参数版本比较)声明方式:

float average(int number, ...);

注意这个省略号,它代表了该函数的可变参数列表。要访问它,我们需要先来了解一下stdarg宏。
头文件中包含了一个类型va_list和三个宏va_start,va_arg和va_end。在这个函数中,我们先要声明一个va_list型变量。声明方式:

va_list next; //va_list 变量名;

接着初始化这个变量。通过调用va_start来初始化这个变量,它的第一个参数是va_list变量的名字,第二个参数是省略号前最后一个有名字的参数(的名字)。初始化方式:

va_start(next, number);

初始化的过程就是把next变量设置为指向可变参数部分的第一个参数。

为了访问可变参数,还需要使用va_arg。这个宏接受两个参数:va_list变量和参数列表中当前参数的类型。va_arg可以返回va_list型参数当前指向的参数的值,并让va_list型参数指向可变参数列表中的下一个参数。va_arg使用方式:

float sum = 0;
for(int i = 0; i < number; i++)
    sum += va_arg(next, int); //next只是一个va_list型变量的名字,并没有特殊意义

为实现可变参数累加,先定义一个浮点型的变量sum并初始化为0,再在每次访问可变参数时让sum加上当前参数并让next指向下一个参数。

最后,在函数末尾,还要用到va_end来“结束”这个va_list型变量,参数就是这个va_list型变量的名字。调用方式:

va_end(next);

最后,只需将计算得到的总和(sum)除以数据个数并返回,即可实现一个计算平均数的函数。

下面给出整个求平均数函数的定义过程:

float average(int number, ...)
{
    //声明va_list型变量
    va_list next;
    //初始化next,使它指向可变参数列表中的第一个参数
    va_start(next, number);
    float sum = 0;
    for(int i = 0; i < number; i++)
    //va_arg返回当前(next指向的)参数并让next指向下一个参数
        sum += va_arg(next, int);
    //调用va_end以“结束”next
    va_end(next);
    return sum / number;
}

3.总结

  1. 使用va_start首先得保证参数列表中至少要有一个命名参数。如果一个命名参数也没有,就无法使用va_start。
  2. 这些宏无法判断实际存在的参数的数量且无法判断每个参数的类型。
  3. 要回答上述两个问题,就必须使用命名参数。如上面的求平均数的函数,命名参数指定了实际传递的参数的数量;再如printf函数中的命名参数是格式字符串,它不仅指定了参数的数量,而且指定了参数的类型。

4.警告
如果再va_arg中指定了错误的类型,那么结果是不可预测的。这个错误是很容易发生的,因为va_arg无法正确识别作用于可变参数之上的缺省参数类型提升。char、short和float类型的值实际上将作为int或double类型的值传递给函数。使用你在va_arg中使用后面这些类型时应该特别小心。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
c语言的宏函数是一种宏定义的形式,可以在编译预处理阶段通过替换来实现类似函数调用的功能。它不同于普通的函数调用,其主要特点是在宏定义时使用一些特殊的宏形参,这些宏形参可以包含可变参数可变参数是指宏函数在调用时可以传入不定数量的参数。在宏定义,我们可以使用"..."来表示可变参数,且该参数必须放置在宏参数列表的最后。 通过宏定义可变参数,我们可以通过宏函数实现一些功能较为复杂的操作。比如,我们可以编写一个求和的宏函数,可以传入任意数量的参数,并对它们进行求和计算。例如: ``` #define SUM(...) sum(__VA_ARGS__) int sum(int count, ...) { int result = 0; va_list arg; va_start(arg, count); for(int i = 0; i < count; i++) { result += va_arg(arg, int); } va_end(arg); return result; } ``` 在使用可变参数的宏函数时,我们需要使用宏定义的特殊宏形参,包括`va_list`、`va_start`、`va_arg`和`va_end`。`va_list`是一个用于存储可变参数的类型,`va_start`用于初始化可变参数的访问,`va_arg`用于按顺序获取可变参数的值,`va_end`用于结束对可变参数的访问。 总之,宏函数可变参数是C语言非常有用的功能,可以通过它们来实现一些复杂的操作和功能。但需要注意的是,在使用可变参数时要小心,保证参数的正确性和合法性,以免出现错误。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值