Va_list Va_start va_arg Va_end 的用法

首先我们先看看它的头文件是怎么描述的

stdarg.h
#pragma once

#ifndef _INC_STDARG
#define _INC_STDARG

#if     !defined(_WIN32)
#error ERROR: Only Win32 target supported!
#endif


#include <vadefs.h>

#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end

#endif  /* _INC_STDARG */
#define _crt_va_arg(ap,t)    (*(t *)((ap += _SLOTSIZEOF(t)+ _APALIGN(t,ap)) \
                                                     -_SLOTSIZEOF(t)))

#include<vadefs.h>
#define _crt_va_arg(ap,t)(*(t *)((ap += _SLOTSIZEOF(t)+_APALIGN(t,ap)) \-_SLOTSIZEOF(t)))
#define _crt_va_end(ap)      ( ap = (va_list)0 )

.va_list用于声明一个变量,我们知道函数的可变参数列表其实就是一个字符串,所以va_list才被声明为字符型指针,这个类型用于声明一个指向参数列表的字符型指针变量
va_start(ap,v),它的第一个参数是指向可变参数字符串的变量,第二个参数是可变参数函数的第一个参数,通常用于指定可变参数列表中参数的个数。
va_arg(ap,t),它的第一个参数指向可变参数字符串的变量,第二个参数是可变参数的类型。
va_end(ap) 用于将存放可变参数字符串的变量清空(赋值为NULL).

接下来看一个例子

static struct ExprNode * MakeExprNode(enum Token_Type opcode, ...) {

struct ExprNode *ExprPtr = new (struct ExprNode);
va_list ArgPtr;

    ExprPtr->OpCode = opcode; // 接受记号的类别

    va_start(ArgPtr, opcode);

    switch(opcode) {    // 根据记号的类别构造不同的节点
        case CONST_ID: // 常数
            ExprPtr->Content.CaseConst = (double)va_arg(ArgPtr, double);
            break;

        case T:
            ExprPtr->Content.CaseParmPtr = &Parameter;
            break;

        case FUNC:
            ExprPtr->Content.CaseFunc.MathFuncPtr = (FuncPtr)va_arg(ArgPtr, FuncPtr);
            ExprPtr->Content.CaseFunc.Child = (struct ExprNode *) va_arg(ArgPtr, struct ExprNode *);
            break;

        default:
            ExprPtr->Content.CaseOperator.Left = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);
            ExprPtr->Content.CaseOperator.Right = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);
            break;
    }

    va_end(ArgPtr);

    return ExprPtr;
}

上述代码是语法分析的生成语法树的一个实现代码;通过这段代码我们能看清楚的是
va_start的功能是要把ap指针指向可变参数的第一个参数位置去
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
. va_arg是要从ap中取下一个参数,即第一个参数。以此类推。
#define _crt_va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
注意加粗的ap 实际上是等于 ap = ap + ……;
. va_end(ap) 将声明的ap指针置为空,因为指针使用后最后设置为空

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值