VA_LIST介绍以及VA_START、VA_ARG、VA_END的用法

VA_LIST 是在c语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>
变量定义:
#ifdef _M_ALPHA
typedef struct {
char *a0; /* pointer to first homed integer argument */
int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif
_M_ALPHA是指DEC ALPHA(Alpha AXP)架构。所以一般情况下va_list所定义变量为字符指针。

几个宏定义:
INTSIZEOF 宏 ,获取类型占用的空间长度,最小占用长度为int的整数倍:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

VA_END宏,清空va_list可变参数列表:
#define va_end(ap) ( ap = (va_list)0 )

函数参数的传递原理:

函数参数是以数据结构:栈的形式存取,从右至左入栈;

举例说明:

先介绍一下可变参数表的调用形式以及原理:
首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:
    void func(int x, float y, char z);
那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。



用法:
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
        在调用参数表之前,定义一个 va_list 类型的变量,(假设va_list 类型变量被定义为ap)
         例如:va_list ap
 
(2)然后用VA_START宏初始化刚定义的VA_LIST变量
         然后应该对ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个                           
        参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数;
         例如:
                假设可变参数函数定义如下:int fun(int start,...)包括一个固定参数为int类型的start变量。
                va_start( ap, start)
                此时的ap执行start下一个可变参数的地址。

(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用      
         VA_ARG获取各个参数);
       然后是 获取参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且  
      把 ap 的位置指向变参表的下一个变量位置;
          例如:
                假设可变参数函数定义如下:int fun(int start,...)包括一个固定参数为int类型的start变量。
                va_start( ap, start)
                此时的ap为start下一个可变参数的地址。
                va_arg( ap, int)
                此时ap为start下两个可变参数的地址,每执行一次va_arg,ap地址指向当前可变参数的下一个参数地址,    
                同时返回当前地址的可变参数的值;
                
(4)最后用VA_END宏结束可变参数的获取。
                例如: va_end(ap);


测试代码实例:test.c

#include<stdarg.h>
#include<stdio.h>
int sum(int,...);
int main()
{
   printf("Sum of 25 and 32 = %d",  sum(2, 25, 32));
    return0;
 }
int sum(int num_args,...)
{int val =0;
   
   va_list ap;
   int i;

   va_start(ap, num_args);//ap指向第一个可变参数的地址
   for(i =0; i < num_args; i++)
   {
      val += va_arg(ap,int);//返回当前ap地址的值,并且将ap指向下一个可变参数的地址
   }
   va_end(ap);//结束获得可变参数
    return val;
}

让我们编译和运行上面的程序,这将产生以下结果:

gcc test.c -o test 

./test

Sum of 25 and 32 = 57




 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值