stdarg宏用法--------可变参数调用
stdarg宏------可变参数调用,定义于stdarg.h头文件,是标准库的一部分,这个主要在一些内核代码中经常看到,这个头文件声明了类型va_list和三个宏-----va_start,va_arg,va_end。一般声明一个va_list的变量,与这几个宏配合使用,访问参数的值。
var_arg用来访问参数列表的未确定部分,这个变量通过调用va_start来初始化。
va_start函数的第一个参数是va_list变量的名字,第二个参数是省略号前最后一个有名字的参数。初始化过程把var_arg变量设置为指向可变参数部分的第一个参数。
va_arg,这个宏接受两个参数:va_list变量和参数列表中下一个参数类型。va_arg返回这个参数的值,并使var_arg指向下一个可变参数。
在访问完最后一个可变参数之后,需要调用va_end。
函数在堆栈中的分布情况是:地址从高到低,依次是函数参数列表,函数返回地址,函数执行代码
堆栈中哦,各个函数的分布情况是倒序的
参数在堆栈中的分布情况如下:
最后一个参数
倒数第二个参数
…
第一个参数
函数返回地址
函数代码段
#include<stdarg.h>
#include<stdio.h>
void simple_va_fun(int a,...)
{
va_list arg_ptr;
va_start(arg_ptr,a); //第一个可选参数地址
for(int i=0;i<a;i++)
{
int k=va_arg(arg_ptr,int); //VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
printf("%d\n",k);
}
va_end(arg_ptr); //将指针置为无效
return;
}
int main()
{
simple_va_fun(2,20,30);
printf("\n");
simple_va_fun(3,20,30,40);
return 0;
}
运行结果如下:
20
30
20
30
40
再对比下面的这个代码
#include<stdarg.h>
#include<stdio.h>
void simple_va_fun(int b,int a,...) //区别,多了一个参数
{
va_list arg_ptr;
va_start(arg_ptr,a); //第一个可选参数地址
for(int i=0;i<a;i++)
{
int k=va_arg(arg_ptr,int); //VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
printf("%d\n",k);
}
va_end(arg_ptr); //将指针置为无效
return;
}
int main()
{
simple_va_fun(3,2,20,30); //这里相应的多了一个参数
printf("\n");
simple_va_fun(4,3,20,30,40);
return 0;
}
再看运行结果:
20
30
20
30
40
也就是说va_start的第二个参数只对省略号前最后一个有名字的参数有效,与前面有名字的参数并无关系。