VA_LIS 是在C语言中解决【变参问题】的一组宏,【变参问题】是指参数的个数不定,
可以传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;
可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。
其中va_list( VA_LIST 是在C语言中解决变参问题的一组宏):va_list表示可变参数列表类型,实际上就是一个char指针fmt。
下面是va_list的用法示例
1 #include <stdargs.h> 2 #include <stdio.h> 3 4 float retAve(int cnt, ...); 5 6 int main() 7 { 8 printf("1~5's ave is %.1f", retAve(5, 1, 2, 3, 4, 5)); 9 return 0; 10 } 11 12 float retAve(int cnt, ...) 13 { 14 valist ap; 15 int i = cnt; 16 float ret = 0; 17 va_start(ap, cnt); 18 19 while(i--) 20 { 21 ret += va_arg(ap, int); 22 } 23 return ret/(float)cnt; 24 }
VA_LIST的用法:
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
(4)最后用VA_END宏结束可变参数的获取。
上面是va_list的具体用法,下面讲解一下va_list各个语句含义(如上示例黑体部分)和va_list的实现。
va_list ap; //定义一个 va_list 变量ap va_start (ap,v); //执行ap = ( va_list )&v + _INTSIZEOF(v),ap指向参数v之后的那个参数的地址,即ap指向第一个可变参数在堆栈的地址。 va_arg (ap,t) //取出当前ap指针所指的值,并使ap指向下一个参数。ap+=sizeof (t类型),让ap指向下一个参数的地址。 //然后返回ap- sizeof (t类型)的t类型指针,这正是第一个可变参数在堆栈里的地址。然后用取得这个地址的内容。 va_end (ap); // 清空 va_list ap。
可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是VC6.0中x86平台的定义:
typedef char * va_list; // TC中定义为void* #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) //为了满足需要内存对齐的系统 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一个变参的位置,即将第一个变参的地址赋予ap #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //获取变参的具体内容,t为变参的类型,如有多个参数,则通过移动ap的指针来获得变参的地址,从而获得内容 #define va_end(ap) ( ap = (va_list)0 ) //清空va_list,即结束变参的获取
C语言的函数形参是从右向左压入堆栈的,以保证栈顶是第一个参数,而且x86平台内存分配顺序是从高地址到低地址。因此似函数AVEInt(int var1,intvar2,…,int varN)内存分配大致上是这样的:(可变参数在中间)
标签:va,VA,变参,list,ap,实例,参数 From: https://www.cnblogs.com/FBsharl/p/17607158.html