Pointers on C——7 Functions.8

7.6 Variable Argument Lists

可变参数列表


A function prototype lists the arguments that the function expects, but a prototype can only show a fixed number of arguments. Is it possible for a function to accept a different number of arguments at different times? Yes, but there are some restrictions.Consider a function that computes the average of a series of values. This task is trivial if the values are stored in an array, so to make the problem more interesting letʹs assume that they are not. Program 7.9a attempts to do the job.

在函数的原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数。让一个函数在不同的时候接受不同数目的参数是不是可以呢?答案是肯定的,但存在一些限制。考虑一个计算一系列值的平均值的函数。如果这些值存储于数组中,这个任务就太简单了,所以为了让问题变得更有趣一些,我们假定它们并不存储于数组中。程序7.9a 试图完成这个任务。

This function has several problems. First, there isnʹt a test for too many  arguments, but one could easily be added. Second, the function cannot handle more than five values. This problem can only be rectified by adding even more copies of the already redundant code.

But there is a more serious problem which occurs when you try to call the function like this:

这个函数存在几个问题。首先,它不对参数的数量进行测试,无法检测到参数过多这种情况。不过这个问题很好解决,简单加上测试就是了。其次,函数无法处理超过5 个的值。要解决这个问题,你只有在已经很臃肿的代码中再增加一些类似的代码。


avg1 = average( 3, x, y, z );


There are only four arguments, but the function has six formal parameters. The Standard covers this situation: the behavior is undefined. Thus, the first argument might correspond to the n_values parameter or maybe to the v2 parameter. You can certainly test your implementation to see what it does, but the program is certainly not portable. What is need is a mechanism to access an unbounded argument list in a welldefined way.

这里只有4 个参数,但函数具有6 个形参。标准是这样定义这种情况的,这种行为的后果是未定义的。这样,第1 个参数可能会与n_values 对应,也可能与形参v2 对应。你当然可以测试一下你的编译器是如何处理这种情况的,但这个程序显然是不可移植的。我们需要的是一种机制,它能够以一种良好定义的方法访问数量未定的参数列表。

/*

** Compute the average of the specified number of values (bad).

*/

float

average( int n_values, int v1, int v2, int v3, int v4, int v5 )

{

float sum = v1;

if( n_values >= 2 )

sum += v2;

if( n_values >= 3 )

sum += v3;

if( n_values >= 4 )

sum += v4;

if( n_values >= 5 )

sum += v5;

return sum / n_values;

}

Program 7.9a Compute the average of scalar values: bad version

7.6.1 The stdarg Macros

Variable argument list are implemented using macros defined in the stdarg.h header, which is part of the standard library. The header declares a type va_list and three macros – va_start, va_arg, and va_end. A variable of type va_list is declared and used with the macros to access the argument values.

可变参数列表是通过宏来实现的,这些宏定义于stdarg.h 头文件,它是标准库的一部分。这个头文件声明了一个类型va_list 和三个宏——va_start、va_arg和va_end 。我们可以声明一个类型为va_list 的变量,与这几个宏配合使用,访问参数的值。

/*

** Compute the average of the specified number of values.

*/

#include <stdarg.h>

float

average( int n_values, ... )

{

va_list var_arg;

int count;

float sum = 0;

/*

** Prepare to access the variable arguments.

*/

va_start( var_arg, n_values );

/*

** Add the values from the variable argument list.

*/

for( count = 0; count < n_values; count += 1 ){

sum += va_arg( var_arg, int );

}

/*

** Done processing variable arguments.

*/

va_end( var_arg );

return sum / n_values;

}


Program 7.9b Compute the average of scalar values: good version Program 7.9b uses these macros to correctly accomplish what program 7.9a tried to do. Notice the ellipsis in the argument, list: it indicates that an unspecified number of arguments with unspecified types may be passed. The same notation is used when prototyping the function.

程序7.9b 使用这三个宏正确地完成了程序7.9a 试图完成的任务。注意参数列表中的省略号:它提示此处可能传递数量和类型未确定的参数。在编写这个函数的原型时,也要使用相同的记法。


The function declares a variable called var_arg with which to access the unspecified portion of the argument list. This variable is initialized by calling va_start. The first parameter is the name of the va_list variable, and the second parameter is the last named argument before the ellipsis. This initialization sets the var_arg variable to point to the first of the variable arguments.

函数声明了一个名叫var_arg 的变量,它用于访问参数列表的未确定部分。这个变量通过调用va_start 来初始化。它的第1 个参数是va_list 变量的名字,第2 个参数是省略号前最后一个有名字的参数。初始化过程把var_arg 变量设置为指向可变参数部分的第1 个参数。


To access an argument, va_arg is used. This macro takes two parameters: the va_list variable and the type of the next value in the list. In this example, the variable arguments are all integers. In some functions, you may have to determine the type of the next argument by examining previously obtained data.va_arg returns the value of this argument and advances var_arg to point to the next variable argument.

为了访问参数,需要使用va _arg ,这个宏接受两个参数: va_list 变量和参数列表中下一个参数的类型。在这个例子中,所有的可变参数都是整型。在有些函数中,你可能要通过前面获得的数据来判断下一个参数的类型 。var_arg 返回这个参数的值,并使var_arg 指向下一个可变参数。


Finally, va_end is called after the last access to the variable arguments.

最后,当访问完毕最后一个可变参数之后,我们需要调用va_end 。

上一章 Pointers on C——7 Functions.7

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值