Поделиться через


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_copy, va_start и va_end не возвращают значений.

Заметки

Макросы va_arg, va_copy, va_end и va_start предоставляют переносимый способ получения аргументов функции, которая принимает переменное число аргументов. Есть две версии макросов: Макросы, определенные в STDARG.H соответствуют стандарту ISO C99; макросы, определенные в VARARGS.H не рекомендуется использовать, но сохранены для обратной совместимости с кодом, который написан до стандарта ANSI C89.

Эти макросы предполагают, что функции принимают фиксированное число обязательных аргументов, за которыми следует переменное число необязательных аргументов. Обязательные аргументы объявляются как обычные параметры для функции и доступными через имена параметров. Доступ к необязательным аргументам осуществляется через макросы в STDARG.H (или VARARGS.H для кода, написанного до стандарта ANSI C89), которые задают указатель на первый необязательный аргумент в списке аргументов, получают аргумент из списка и сбрасывают указатель, когда обработка аргументов завершена.

Стандартные макросы языка C, которые определены в STDARG.H, используются следующим образом:

  • va_start задает arg_ptr на первый необязательный аргументу в списке аргументов, который передан функции. Аргумент arg_ptr должен иметь тип va_list. Аргумент prev_param - это имя обязательного параметра, который непосредственно предшествует первому необязательному аргументу в списке аргументов. Если prev_param объявлен в классе регистрового хранения, поведение макроса не определено. va_start необходимо использовать до того, как va_arg используется в первый раз.

  • va_arg извлекает значение type из местоположения, которое задано arg_ptr и увеличивает arg_ptr, чтобы он указывал на следующий аргумент в списке, используя размер type, чтобы определить, где начинается следующий аргумент. va_arg можно использовать любое количество раз в функции, чтобы получить аргументы из списка.

  • va_copy делает копию списка аргументов в текущем состоянии. Параметр src должна быть уже инициализирован значением va_start; он может обновляться с вызовами va_arg, но не должен быть сброшен с помощью va_end. Следующий аргумент, который извлекается va_arg из dest совпадает со следующий аргументом, который извлекается из src.

  • После того как были получены все аргументы, va_end сбрасывает указатель на NULL. va_end должен вызываться для каждого списка аргументов, который инициализируется va_start или va_copy до выполнения возврата функцией.

Примечание C++Примечание C++

Макросы в VARARGS.H не рекомендуется использовать и сохранены только для обратной совместимости с кодом, который написан до стандарта ANSI C89.Во всех остальных случаях используйте макросы в STDARGS.H.

При компилировании с помощью /clr (компиляция 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