Share via


va_arg、va_copy、va_end、va_start

访问变量参数列表。

type va_arg(
   va_list arg_ptr,
   type 
);
void va_copy(
   va_list dest,
   va_list src
); // (ISO C99 and later)
void va_end(
   va_list arg_ptr 
);
void va_start(
   va_list arg_ptr,
   prev_param 
); // (ANSI C89 and later)
void va_start(
   arg_ptr 
);  // (Pre-ANSI C89 standardization version)

参数

  • type
    要检索的参数的类型。

  • arg_ptr
    指向参数列表的指针。

  • dest
    指向初始化从 src 给参数列表的指针

  • src
    指向参数初始化列表复制到 dest 的指针。

  • prev_param
    优先于第一个可选参数的参数。

返回值

va_arg 返回当前参数。 va_copyva_startva_end 不返回值。

备注

该函数参数时,数目可变 va_argva_copyva_endva_start 宏提供一个可移植的访问方式参数传递给函数。 具有宏的两个版本:在 STDARG.H 中定义的宏与 ISO C99 标准一致;在 VARARGS.H 定义的宏被否决,但用于在 ANSI C89 标准之前编写的向后兼容的代码。

在可选参数的数目可变之后,这些宏假设函数采用所需参数的一个固定数目。 必选参数被声明普通参数传递给函数,并且可以传递参数名访问。 可选参数传入 STDARG.H的宏 (或 VARARGS.H 在 ANSI C89 标准之前编写的代码) ,当参数操作完成时,设置参数列表的第一个可选参数,从列表检索参数,并重置指针。

定义在 STDARG.H的 C 标准宏的使用如下所示:

  • va_start 将 arg_ptr 设置为传递给该函数参数列表的第一个可选参数。 参数 arg_ptr 必须具有 va_list 类型。 参数 prev_param 是参数列表中紧邻第一个可选参数列的必选参数的名称。 如果 prev_param 声明为注册存储类,则宏的行为未定义。 va_start必须在 va_arg 第一次使用前使用。

  • va_arg 从 arg_ptr给出的位置检索 type 的值,并将 arg_ptr 指向列表中的下一个参数,使用 type 的范围确定下一个参数开始的位置。 va_arg 在该函数可以使用任意数量的时间从列表中检索实参。

  • va_copy 复制了其当前状态下的参数列表。 src 参数已经被va_start初始化了;它得调用va_arg来更新,但是,不能使用va_end来重置。 由 va_arg 检索的来自 dest 的下一个参数与来自src的下一个参数相同。

  • 在所有参数检索之后,va_end 重置指向 NULL的指针。 在函数返回之前,必须在初始化 va_startva_copy的每个参数列表之上调用va_end

C++ 说明C++ 说明

弃用 VARARGS.H 的宏,仅保留在 ANSI C89 标准之前编写的向后兼容代码。其他情况下,请使用STDARGS.H中的宏。

使用 /clr(公共语言运行时编译)时,它们被编译,由于本机和公共语言运行时 (CLR) 类型系统之间的差异,使用这些宏的程序可能会产生意外的结果。 考虑此过程:

#include <stdio.h>
#include <stdarg.h>

void testit (int i, ...)
{
    va_list argptr;
    va_start(argptr, i);

    if (i == 0)
    {
        int n = va_arg(argptr, int);
        printf("%d\n", n);
    }
    else
    {
        char *s = va_arg(argptr, char*);
        printf("%s\n", s);
    }
}

int main()
{
    testit(0, 0xFFFFFFFF); // 1st problem: 0xffffffff is not an int
    testit(1, NULL);       // 2nd problem: NULL is not a char*
}

请注意 testit 期望其第二个参数是 int 或 char*。 传递的参数是 0xffffffff ( unsigned int,而不是 int) 和 NULL (实际是 int,而不是 char*)。 当程序进行本机代码的编译时,会生成此输出:

  
  

但是,当使用 /clr:pure编译时,类型不匹配导致其发生异常。 该解决方案是使用显式转换:

int main()
{
   testit( 0, (int)0xFFFFFFFF ); // cast unsigned to int
   testit( 1, (char*)NULL );     // cast int to char*
}

要求

页眉:<stdio.h>和 <stdarg.h>

已弃用标头: <varargs.h>

C 运行时库的所有版本。

示例

// crt_va.c
/* Compile with: cl /W3 /Tc crt_va.c
 * The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_copy
 *      va_end              va_list
 */

#include <stdio.h>
#include <stdarg.h>
#include <math.h>

double deviation(int first, ...);

int main( void )
{
    /* Call with 3 integers (-1 is used as terminator). */
    printf("Deviation is: %f\n", deviation(2, 3, 4, -1 ));

    /* Call with 4 integers. */
    printf("Deviation is: %f\n", deviation(5, 7, 9, 11, -1));

    /* Call with just -1 terminator. */
    printf("Deviation is: %f\n", deviation(-1));
}

/* Returns the standard deviation of a variable list of integers. */
double deviation(int first, ...)
{
    int count = 0, i = first;
    double mean = 0.0, sum = 0.0;
    va_list marker;
    va_list copy;

    va_start(marker, first);     /* Initialize variable arguments. */
    va_copy(copy, marker);       /* Copy list for the second pass */
    while (i != -1)
    {
        sum += i;
        count++;
        i = va_arg(marker, int);
    }
    va_end(marker);              /* Reset variable argument list. */
    mean = sum ? (sum / count) : 0.0;

    i = first;                  /* reset to calculate deviation */
    sum = 0.0;
    while (i != -1)
    {
        sum += (i - mean)*(i - mean);
        i = va_arg(copy, int);
    }
    va_end(copy);               /* Reset copy of argument list. */
    return count ? sqrt(sum / count) : 0.0;
}

Output

  

.NET Framework 等效项

System::ParamArrayAttribute 类

请参见

参考

参数访问

vfprintf、_vfprintf_l、vfwprintf、_vfwprintf_l