第16章 C预处理器和C库 16.13 可变参数:stdarg.h

本文介绍了如何使用可变参数函数,包括使用头文件stdarg.h中的宏实现参数的初始化、访问和清理工作。通过示例程序展示了如何创建一个接受可变数量参数并计算其总和的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章前面讨论了可变宏,该宏接受可变个数的参数。

头文件stdarg.h为函数提供了类似的能力。不过使用方法稍微复杂一些。必须按如下步骤进行:

1、在函数原型中使用省略号

2、在函数定义中创建一个va_list类型的变量

3、用宏将该变量初始化为一个参数列表

4、用宏该问这个参数列表

5、用宏完成清理工作

现在详细讨论这些步骤。这类函数的原型应具有一个参量列表,参量列表中至少有一个后跟省略号的参量

void f1(int n,...);            //合法

int f2(int k,const char *s,...)    //合法

char f3(char c1,...,char c2)     //无效,省略号不是最后一个参量

double f3( );                         //无效,没有任何参量

最右边的参量(省略号前)起着特殊作用;ANSI 使用parmN表示该参量。前例中,第一种情况下parmN为n,第二种情况下parmNo为k。传递给该参量的实际参数值将是省略号部分代表的参数个数。

例如,前面的f1()函数原型可以这样使用:

f1(2,200,400);      //2个额外的参数

f1(4,13,117,18,23); //4个额外的参数

接下来,在头文件stdarg.h中声明的va_list类型代表一种数据对象该数据对象用于存放参量列表中省略号部分代表的参量。可变函数定义的起始部分应像下面这样:

double sum(int lim,...)

{

    va_list ap;    //声明用于存放参数的变量

本例中,lim为参量parmN,由它来指定可变参数列表中的参数个数。

然后,函数将使用stdarg.h中定义的宏va_start( )把参数列表复制到va_list变量中宏va_start()有两个参数:va_list类型的变量和参量parmN。我们接着前一个例子讨论,va_list类型的变量为ap,参量parmN为lim,因此,对va_start()的调用应如下所示:

va_start(ap,lim);    //把ap初始化为参数列表

下一步是访问参数列表中的内容这一步涉及宏va_arg()的使用该宏接受两个参数:一个va_list类型的变量,一个类型名。

第一次调用va_arg()时,它返回参数列表的第一项,下次调用返回第二项,依此类推类型参数指定返回值的类型。例如,如果参数列表中第一个参数为double类型,第二个为int类型,那么可使用如下语句:

double tic;
int toc;
...
tic = va_arg(ap,double);    //取得第一个参数
toc = va_arg(ap,int);       //取得第二个参数

注意,实际参数的类型必须与说明的类型相匹配。如果第一个参数是10.0,那么前面的tic部分的代码正常工作,但是如果参数是10,代码就可能无法工作。这里不会像赋值过程那样进行double到int的自动转换。

最后,应使用va_end()完成清理工作。例如,释放动态分配的用于存放参数的内存。该宏接受一个va_list变量作为参数:

va_end(ap);    //清理工作

此后,只有用va_start()重新对ap初始化后,才能使用变量ap。

因为va_arg()不提供后退回先前参数的方法,所以保存va_list变量的副本是会有用的。C99专门为此添加了宏va_copy()。该宏的两个参数为va_list类型变量,它将第二个参数复制到第一个参数中

va_list ap;
va_list apcopy;
double
double tic;
int toc;
...
va_start(ap,lim);  //把ap初始化为参数列表
va_copy(apcopy,ap);//apcopy是ap的一个副本
tic = va_arg(ap,double);  //取得第一个参数
toc = va_arg(ap,int);     //取得第二个参数

此时,虽然从ap中删除了前两项,但还可以从apcopy中重新获取这两项

程序清单16.18的简短示例程序说明了创建一个这样的函数的方法,该函数对可变参数进行求和运算。sum()的第一个参数是要进行求和运算的项目的个数。

程序清单16.18 varargs.c  程序

//varargs.c  --使用可变个数的参数
#include <stdio.h>
#include <stdarg.h>
double sum(int ,...);

int main()
{
    double s,t;

    s = sum(3,1.1,2.5,13.3);
    t = sum(6,1.1,2.1,13.1,4.1,5.1,6.1);
    printf("return value for "
           "sum(3,1.1,2.5,13.3):                      %g\n",s);
    printf("return value for "
           "sum(6,1.1,2.1,13.1,4.1,5.1,6.1):          %g\n",t);

    return 0;
}

double sum(int lim,...)
{
    va_list ap;      //声明用于存放参数的变量
    double tot=0;
    int i;
    va_start(ap,lim);//把ap初始化为参数列表
    for(i=0;i<lim;i++)
        tot+=va_arg(ap,double);//访问参数列表中的每一项
    va_end(ap);    //清理工作
    return tot;
}

输出如下:

return value for sum(3,1.1,2.5,13.3):                      16.9
return value for sum(6,1.1,2.1,13.1,4.1,5.1,6.1):          31.6

可以发现,第一次调用sum()时对3个数求和,第二次调用时对6个数求和。

总之,可变函数的用法比可变宏更复杂,但是函数的应用范围更广。

转载于:https://my.oschina.net/idreamo/blog/1498400

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值