您的位置:首页 > 编程语言 > C语言/C++

C语言可变参数列表

2016-11-07 12:33 211 查看
c语言函数可变参数列表

在函数原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数。它不对参数的数量进行测试,无法检测参数过多的这种情况;

我们假定它们并不存储于数组中。先来看一个计较差的,也是不太稳定的一个解决方案:

//计算指定数目的值的平均值(差的方案)

float average(int n_value,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;
}


这个函数存在几个问题:首先,它不对参数的数量进行测试,无法检测参数过多的这种情况。不过这个问题容易解决,简单加上测试就是了。其次,函数无法处理超过5个的值。要解决这个问题,你只有在已经很臃肿的代码中再增加一些类似的代码。另外还存在一个更为严重的问题:就是实参数与形参的对应不一定准确。

但是让一个函数在不同的时候接受不同数目的参数是可以的。

stdarg宏

可变参数列表是通过宏来实现的,这些宏定义stdarg.h头文件,它是标准库的一部分。这个头文件声明了一个类型va_list和

三个宏——va_start、va_arg、va_end。我们可以声明一个类型为va_list的变量,与这几个宏配合使用,访问参数的值。

注意参数列表中的省略号:它提示此处可能传递数量和类型未确定的参数,在编写这个函数原型的时候,也要使用相同的记法。

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

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

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

考虑计算一系列值的平均值的函数。如果这些值存储于数组中,这个任务就太简单了,所以为了让问题变得更有趣一些:

1)下面的程序使用三个宏正确的完成计算指定数目的值的平均值的任务。

//指定数量的值的平均值

#include<stdarg.h>
float(int values,...)
{
va_list   var_arg;
int count;
float sum=0;
var_start(var_arg,n_values);//准备访问可变参数
for(count=0;count<n_values;count+=1) //添加取自可变参数表的值
{
sum+=var_varg(var_arg,int);
}
var_end(var_arg);       //完成处理可变参数
return sum/n_values;
}


2)下面的程序使用三个宏正确的完成计算指定数目的值的最大值的任务。

int Max(int n,...)
{
va_list var_arg;
int max=0;
int i=0;
va_start(var_arg,n);
max=va_arg( var_arg,int);
for(i=0;i<n;i++)
{
int temp=va_arg(var_arg,int);
if(temp>max)
{
max=temp;
}
return max;
}
}


在参数列表中至少要有一个命名参数,否则无法使用va_start,这个参数提供了一种方法,用于查找参数列表的可变参数部分。

对于这些宏,存在两个基本的限制。一个值的类型无法简单的通过检查它的位模式来判断,这两个限制就是这个事实的直接结果。

1.这些宏无法判断实际存在的参数的数量。

2.这些宏无法判断每个参数的类型。要回答这两个问题,就必须使用命名参数,命名参数指定了实际传递的参数。printf函数中的命名参数是格式字符串,它不仅指定了参数的数量,而且指定了参数的类型。

警告:

如果在va_arg中指定了错误的类型,那其结果是不可预料的,这个错误很容易发生,因为va_arg无法正确识别作用于可变参数之上的缺省参数类型提升。char,short,float类型的值,实际上将作为int 或double类型的值传递给函数,所以你在va_arg中使用后面这些类型时应该小心。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: