c语言实现函数的可变参数

作者: dreamfly 分类: 个人博客 发布时间: 2019-03-30 10:26

有时候,我们希望我们的函数的参数是动态变化的。例如:

int func(int,..)

int func(2,1,2)

int func(3,2,2,9)

我们可以通过制定参数的个数,来动态添加参数。那么c语言是如何实现这个功能的呢?c语言提供了标准函数库,我们只需要引入stdarg.h这个头文件就可以了。

下面介绍如何正确使用这个功能。

  • 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。

  • 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。

  • 使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。宏 va_start 是在 stdarg.h 头文件中定义的。

  • 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。

  • 使用宏 va_end 来清理赋予 va_list 变量的内存。

  

具体代码如下:

#include <stdio.h>
#include <stdarg.h>

double average(int num,…){
va_list valist;
double sum = 0.0;
int i;
/* 为 num 个参数初始化 valist */
va_start(valist, num);
/* 访问所有赋给 valist 的参数 */
for (i = 0; i < num; i++)
{
sum += va_arg(valist, int);
}
/* 清理为 valist 保留的内存 */
va_end(valist);
return sum/num;
}
int main(){
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}

其实我们如果深入研究就会发现,valist其实是个指针,它通过不断指向后面的可变参数来获取参数的值,它是通过第一个参数来确定循环的次数的,也就是说,上面我们的函数第一个参数如果为3,后面的参数即使有100个,它也只会取前面3个的平均值。

我们看下va底层是如何定义实现的。

#define _INTSIZEOF(n)      ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) – 1) )

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )              //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) – _INTSIZEOF(t)) ) //下一个参数地址
#define va_end(ap)       ( ap = (va_list)0 )                               // 将指针置为无效

我们看到通过va_arg这个函数,我们就可以获取下一个参数的地址,因为参数的类型不确定,所以我们用sizeof(t)来获取占用位置大小。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注