Windows编程(5)-简述va_list, va_start, va_end

来源:互联网 发布:js实现购物车加减特效 编辑:程序博客网 时间:2024/04/29 11:27

1. 概述:

    VA_LIST是在C语言中解决变参问题的一组宏,在头文件 stdarg.h 中定义。

2. 成员


(1)va_list型变量

    #ifdef _M_ALPHA

    typedef struct {

    char *a0; /* pointer to first homed integer argument */

    int offset; /* byte offset of next parameter */

    } va_list;

    #else

    type char *va_list;

    #endif 

_M_ALPHA 是指DEC ALPHA( Alpha AXP)架构。 所以一般情况下,va_list所定义变量为字符指针。


(2)INTSIZEOF宏

  获取类型占用的空间长度,最小占用长度为int的整数倍:

  #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) -1) & ~( sizeof(int) -1))


(3)va_start 宏

  获取可变参数列表的第一个参数的地址。


(4)va_arg宏

  获取可变参数的当前参数,返回指定类型并将指针指向下一个参数。


(5)va_end宏

  清空va_list可变参数列表

3. 参数在堆栈中分布位置

  在进程中,堆栈地址是从高到低分配的。当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数的返回地址,执行自己的代码。

  总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段。

  堆栈中,各个函数的分布情况是倒序的,即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分。参数在堆栈中的分布情况如下:

最后一个参数

倒数第二个参数

....

第一个参数

函数返回地址

函数代码段

4. 用法

(1)首先在函数里定义一个va_list型的变量, 这个变量时指向参数的指针

(2)然后用va_start宏初始化刚定义的va_list变量

(3)然后用va_arg返回可变的参数,va_arg的第二个参数是你要返回的参数的类型(如果函数有多个可变参数,一次调用va_arg获取各个参数)

(4)最后用va_end宏结束可变参数的获取

5. 注意问题

(1)可变参数的类型和个数完全由程序代码控制,它并不智能地识别不同参数的个数和类型;

(2)如果我们不需要一一详解每个参数,只需要将可变列表拷贝至某个缓冲,可用vsprintf函数;

(3)因为编译器对可变参数的函数原型检查不够严格,对编程查错不利,不利于我们写出高质量的代码。