zoukankan      html  css  js  c++  java
  • 1、va_arg, va_end, va_start的用法用结

        今天看别人写的代码,其中涉及有va_arg, va_end, va_start部分。于是翻阅了一些资料,总结了一下。 

    由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;于是人们想出了用指针参数来解决问题。关于这一部分标准库的定义,VSunix定义的是不一样的,可以参见MSDN关于这一部分的解释。 

    type va_arg( va_list arg_ptr, type ); 

    void va_end( va_list arg_ptr ); 

    void va_start( va_list arg_ptr ),  (UNIX version) 

    void va_start( va_list arg_ptr, prev_param );   (ANSI version)

    MSDN中)

    其中的参数解释如下:

    type Type of argument to be retrieved

    arg_ptr Pointer to list of arguments

    prev_param Parameter preceding first optional argument (ANSI only)

    va_arg Macro to retrieve current argument

    va_end Macro to reset arg_ptr

    va_list typedef for pointer to list of arguments defined in STDIO.H

    va_start Macro to set arg_ptr to beginning of list of optional arguments (UNIX version only)

    VC中,其定义如下:

    typedef char *  va_list;

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

    #define va_start(apv) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址

    #define va_arg(apt) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址

    #define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效

    网友于上述程序中关键地方的解释:

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

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

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

    最后一个参数

    倒数第二个参数

    ...

    第一个参数

    函数返回地址

    函数代码段

    主要函数介绍:

    va_start 使argp指向第一个可选参数。va_arg返回参数列表中的当前参数并使argp指向参数列表中的下一个参数。va_endargp指针清为 NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。

    va_start  sets arg_ptr to the first optional argument in the list of arguments passed to the function. The argument arg_ptr must have va_list type. The argument prev_param is the name of the required parameter immediately preceding the first optional argument in the argument list. If prev_param is declared with the register storage class, the macro’s behavior is undefined. va_start must be used before va_arg is used for the first time.

    va_arg retrieves a value of type from the location given by arg_ptr and increments arg_ptr to point to the next argument in the list, using the size of type to determine where the next argument starts. va_arg can be used any number of times within the function to retrieve arguments from the list.

      After all arguments have been retrieved, va_end resets the pointer to NULL

    示例代码

     

    代码
    1 #include <stdio.h>
    2  #define ANSI /* Comment out for UNIX version */
    3 #ifdef ANSI /* ANSI compatible version */
    4 #include <stdarg.h>
    5 int average( int first, ... ); /* ANSI compatible version */
    6 int average( int first, ... )
    7 {
    8 int count = 0, su
    9 m = 0, i = first;
    10 va_list marker;
    11
    12 va_start( marker, first ); /* Initialize variable arguments. */
    13 while( i != -1 )
    14 {
    15 sum += i;
    16 count++;
    17 i = va_arg( marker, int);
    18 }
    19 va_end( marker ); /* Reset variable arguments. */
    20 return( sum ? (sum / count) : 0 );
    21 }
    22 #endif
    23 void main( void )
    24 {
    25 /* Call with 3 integers (-1 is used as terminator). */
    26 printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );
    27
    28 /* Call with 4 integers. */
    29 printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );
    30
    31 /* Call with just -1 terminator. */
    32 printf( "Average is: %d\n", average( -1 ) );
    33 }
    说明:我的VS2005头文件中宏定义如下:

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

    #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

    #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

    #define _crt_va_end(ap) ( ap = (va_list)0 )

    其中:

    #ifdef __cplusplus

    #define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )

    #else

    #define _ADDRESSOF(v) ( &(v) )

    #endif

    ***********

    #define va_start _crt_va_start

    #define va_arg _crt_va_arg

    #define va_end _crt_va_end

    参考

    [1] MSDN

    [2] http://topic.csdn.net/u/20100711/15/C28B9247-D381-4525-92C0-6725BDB34A08.html

    [3] http://www.cnblogs.com/wubiyu/archive/2008/07/30/1256860.html

     

     

  • 相关阅读:
    三、类的实例方法(阶段三)
    二、类的构造方法(阶段三)
    一、对象与类的区别(阶段三)
    五、数组(阶段二)
    四、(续)流程控制--while for(阶段二)
    四、流程控制--if else和switch(阶段二)
    Java 自带的加密类MessageDigest类(加密MD5和SHA)
    java实现微信扫一扫详解
    springmvc字符编码过滤器CharacterEncodingFilter浅析
    Spring的初始化:org.springframework.web.context.ContextLoaderListener
  • 原文地址:https://www.cnblogs.com/mydomain/p/1785667.html
Copyright © 2011-2022 走看看