可变参数列表剖析

xiaoxiao2021-02-28  86

可变参数列表剖析

在函数的原型中,列出了函数期望接受的参数,单元形只能显示固定数目的参数。让一个函数在不同的时候接受不同数目的参数是不是可以呢?答案是肯定的,但存在一些限制。

举个例子:

float_average(int n,int v1,int v2,int v3,int v4,int v5) { float sum = v1; if(n>2) sum += v2; if(n>3) sum += v3; if(n>4) sum += v4; if(n>5) sum += v5; return sum/n; }

这个函数存在很多缺陷,首先,它不对参数数量进行测试,无法检测到参数过多的这种情况。其次,它无法处理超过五个的值。

当你试图用下面这种形式调用这个函数时,还会存在更严重的一个问题:

int avg = average(3,1,2,3);

这里只存在四个参数,但函数具有6个形参。

为了解决这个问题,我们需要一种机制,他能够以一种良好的定义方式访问参数未定的参数列表。

stdarg 宏

可变参数列表是通过宏实现的,这些宏定义于 stdarg.h 头文件。这个头文件声明了一个类型 va_list 和三个宏va_start,va_arg,va_end。


同样是求平均数,让我们看一段代码

#include<stdio.h> #include<stdarg.h> int average(int n, ...) { va_list arg; int i = 0; int sum = 0; va_start(arg, n) for(i=0;i<n;i++) sum += va_arg(arg, int); va_end(arg); return sum/n; } int main() { int ret = average(5,1,2,3,4,5); return 0; }

va_list定义了一个arg变量,它用于访问参数列表未确定的部分。va_start对其进行初始化,其第一个参数是va_list变量的名字,第二个参数是省略号前第一个有名字的参数。在初始化的过程,arg被设置为指向可变参数部分第一个参数。为了访问访问参数,我们需要使用va_arg。这个宏接受两个参数,va_list定义的参数和列表中下一个参数的类型。va_arg返回这个参数的值,并且指向下一个可变参数。最后,访问完最后一个参数时,需要调用va_end将指针置为无效。

va_start宏的定义如下

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

_INTSIZEOF(n)作用:将n的长度化为int长度的整数倍。

va_arg宏定义如下

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

va_arg作用:返回参数的值,并使arg指向下一个参数。

va_end定义如下

#define va_end(ap) ( ap = (va_list)0 )

va_end作用:指针置为无效。

注意:可变参数列表必须按照顺序从头到尾逐个访问,当你在访问几个可变参数后想半途中止,这是可以的。但是如果你一开始就想访问中间的参数,那是不行的。

转载请注明原文地址: https://www.6miu.com/read-73686.html

最新回复(0)