16.13 可变参数:stdarg.h

本章前面部分讨论了可变宏,该宏接受可变个数的参数。头文件stdarg.h为函数提供了类似的能力。不过使用方法稍微复杂一些。必须按如下步骤进行:

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

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

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

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

4.用宏访问这个参数列表。

5.用宏完成清理工作。

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

阅读 ‧ 电子书库

最右边的参量(省略号前)起着特殊的作用;ANSI标准使用parmN表示该参量。前例中,第一种情况下parmN为n,第二种情况下parmN为k。传递给该参量的实际参数值将是省略号部分代表的参数个数。例如,前面的f1()函数原型可以这样使用:

阅读 ‧ 电子书库

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

阅读 ‧ 电子书库

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

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

阅读 ‧ 电子书库

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

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

阅读 ‧ 电子书库

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

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

阅读 ‧ 电子书库

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

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

阅读 ‧ 电子书库

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

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

程序清单 16.18 varargs.c程序

阅读 ‧ 电子书库

输出如下:

阅读 ‧ 电子书库

查看上面的计算,可以发现第一次调用sum()时对3个数求和,第二次调用时对6个数求和。

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