什么是可变参数函数
C语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function)。这种函数需要固定数量的强制参数,后面是数量可变的可选参数。其中,强制参数必须至少一个,可选参数数量可变,类型可变,可选参数的数量由强制参数的值决定。
C 语言中最常用的可变参数函数例子是 printf()和 scanf()。这两个函数都有一个强制参数,即格式化字符串。格式化字符串中的转换修饰符决定了可选参数的数量和类型。
可变参数函数格式:int fun(int a,...)
可变参数函数的引入
我们可以先简单用我们已知的信息,构造一个累加函数(可变参数)
代码语言:javascript复制int sum(int addnum,...)
{
int i =0;
int res = 0;
for(i;i<addnum;i )
{
res =??
}
}
大概就是这样子,但是有一个问题,可变参数没有参数名 我们又怎么通过代码来访问这些参数呢?
可变参数的获取
我先粘贴一下微软给我们的办法:
代码语言:javascript复制当编写可变参数函数时,必须用 va_list 类型定义参数指针,以获取可选参数。可变参数函数要获取可选参数时,必须通过一个类型为 va_list 的对象来进行访问,它包含了参数信息。这种类型的对象也称为参数指针(argument pointer),它包含了栈中至少一个参数的位置。可以使用这个参数指针从一个可选参数移动到下一个可选参数,由此,函数就可以获取所有的可选参数。va_list 类型被定义在头文件 stdarg.h 中。
研究过堆栈的都知道参数也是会被压入堆栈中的,根据压入方式不同(涉及调用约定 我这里先不提)因为他是被按顺序压入的,我们只要通过va_list这个参数指针指向已经存在的最后一个强制参数,通过移动指针就可以访问到可变参数,这里简单说明一下,后面我会说明函数的调用约定。
现在引入两个函数实现上面的想法:
void va_start(va_list argptr, lastparam);
该函数的第一个参数是一个va_list 类型的指针,第二个参数是可变参数函数中最后一个强制参数,即第一个可选参数前的强制参数。实现了指针指向最后一个强制参数,该函数会初始化指针argptr
type va_arg(va_list argptr, type);
其第一个参数是已经初始化完成的va_list指针,第二个参数则为可变参数的类型,返回的参数就是当前va_list指针所指的可变参数,所以类型也跟传入的可变参数类型相同。访问完一个可变参数会后移指向下一个可变参数
va_end
当不再需要使用参数指针时,必须调用宏 va_end。如果想使用宏 va_start 或者宏 va_copy 来重新初始化一个之前用过的参数指针,也必须先调用宏 va_end。
代码示例:
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
int sum(int n, ...)
{
int i = 0;
int res = 0;
va_list arg;
va_start(arg, n);
for (size_t i = 0; i < n; i )
{
res = va_arg(arg, int);
}
va_end(arg);
return res;
}
int main()
{
int addsum = 0;
addsum = sum(5, 2, 3, 4, 5, 6);
printf("%dn", addsum);
}
上述方法不能智能识别不同参数的个数和类型。
如果想实现智能识别可变参数,比如printf,需要在自己的程序中作特殊处理 具体方法我这里就不介绍了,以后遇到会单独写一篇文章。 感兴趣的可以看一下这篇文章:https://blog.csdn.net/xiaolong_lili/article/details/114708390 明白数据在内存中的存储很容易理解。