Документация Linux www.linuxdoc.ru

STDARG(3)                                               STDARG(3)



НАЗВАНИЕ
       stdarg - переменные списки аргументов

СИНТАКСИС
       #include <stdarg.h>

       void va_start(va_list ap, last);
       type va_arg(va_list ap, type);
       void va_end(va_list ap);
       void va_copy(va_list dest, va_list src);

ОПИСАНИЕ
       Возможен  вызов функции с различным количеством аргументов
       и разных типов. В файле stdarg.h определяется тип  va_list
       и  описываются три макроса для обработки списка аргументов
       с такими значениями  и  таких  типов,  которые  неизвестны
       вызываемой функции.

       Вызванная  функция  должна указать на объект типа va_list,
       который используется макросами va_start, va_arg и  va_end.

   va_start
       Макрос   va_start  должен  вызываться  в  первую  очередь,
       поскольку  он  инициализирует  ap  для  последующего   его
       использования макросами va_arg и va_end.

       Параметр  last  является именем последнего параметра перед
       переменным списком аргументов; например, именем последнего
       параметра, тип которого известен вызывающей функции.

       Так  как  адрес  этого  параметра может быть использован в
       макросе va_start,  то  он  не  должен  быть  объявлен  как
       зарегистрированная переменная, функция или тип массива.

   va_arg
       Макрос va_arg возвращает выражение, которое имеет такой же
       тип и  значение,  как  и  следующий  по  вызову  аргумент.
       Параметр  ap  является  va_list  ap , инициализированным с
       помощью макроса va_start.  Каждый вызов va_arg изменяет ap
       так,  что следующий вызов возвращает последующий аргумент.
       Параметр type является типом, определенным таким  образом,
       что  указатель  на  обьект  этого  типа может быть получен
       простым добавлением * к type.

       Первый  вызов  макроса   va_arg   сразу   после   va_start
       возвращает  аргумент после last.  Последующие вызовы будут
       возвращать величины оставшихся аргументов.

       Если нет следующего аргумента или если type несовместим  с
       типом  следующего аргумента, то могут возникнуть различные
       ошибки.

       Если ap передается функции, использующей  va_arg(ap,type),
       то   значение  ap  будет  неопределено  после  возвращения
       функции.

   va_end
       Каждый вызов va_start должен сопровождаться вызовом va_end
       в той же функции. После вызова va_end(ap) переменная ap не
       определена.  Возможны  множественные  пересечения  списка,
       обособленные  скобками от va_start и va_end.  va_end может
       быть и функцией и макросом.

   va_copy
       va_list является указателем на стек  функции  с  различным
       количеством  аргументов.   В  таких  случаях  используется
       выражение
                   va_list aq = ap;
       К сожалению, существуют системы, которые превращают его  в
       массив указателей (длиной 1), поэтому еще необходимо
                   va_list aq;
                   *aq = *ap;
       И  в  завершении,  в  системах, передающих параметры через
       регистры, возможно появится необходимость в  va_start  для
       выделения памяти, сохранению там параметров и указателе на
       следующие  параметры,  поэтому  может   использоваться   и
       va_arg.     va_end   высвободит   память   обратно.    Для
       уравновешивания  этой  ситуации  в  C99  добавлен   макрос
       va_copy,   после   чего   вышеописанные   выражения  могут
       выглядеть так:
                   va_list aq;
                   va_copy(aq, ap);
                   ...
                   va_end(aq);
       Каждый вызов va_copy должен быть парным с  вызовом  va_end
       для  каждой  функции.  В некоторых системах вместо va_copy
       существует __va_copy.

ПРИМЕРЫ
       Функция foo  принимает  строку  форматирующих  символов  и
       выводит   аргументы,   ассоциированные  с  соответствующим
       символом по типу.

              void foo(char *fmt, ...) {
                   va_list ap;
                   int d;
                   char c, *p, *s;
                   va_start(ap, fmt);
                   while (*fmt)
                        switch(*fmt++) {
                        case 's':           /* строка */
                             s = va_arg(ap, char *);
                             printf("строка %s\n", s);
                             break;
                        case 'd':           /* целое */
                             d = va_arg(ap, int);
                             printf("целое %d\n", d);
                             break;
                        case 'c':           /* символ */
                             /* необходимо указание типов, т.к. va_arg
                             воспринимает только полностью определенные типы */
                             c = (char) va_arg(ap, int);
                             printf("символ %c\n", c);
                             break;
                        }
                   va_end(ap);
              }

СООТВЕТСТВИЕ СТАНДАРТАМ
       Макросы  va_start,  va_arg  и  va_end  соответствуют  ANSI
       X3.159-1989 (``C89'').  C99 определяет макрос va_copy.

СОВМЕСТИМОСТЬ
       Эти  макросы  не  являются  совместимыми  с  более ранними
       реализациями.  Совместимые реализации можно найти в  файле
       заголовков varargs.h.

COMPARISON
       Исторически   сложившийся   синтаксис  выглядит  следующим
       образом:

              void foo(va_alist) va_dcl {
                   va_list ap;

                   va_start(ap);
                   while(...) {
                        ...
                        x = va_arg(ap, type);
                        ...
                   }
                   va_end(ap);
              }
       В некоторых системах va_end  содержит  завершающий  символ
       '}'  соответствующий  '{'  в  va_start, таким образом, оба
       макроса заключены в одной функции.

НАЙДЕННЫЕ ОШИБКИ
       В отличие от макроса varargs, макрос stdarg  не  позволяет
       программистам   создавать   функции   без   фиксированного
       количества аргументов. В основном проблемы  возникают  при
       конвертировании  исходных кодов с varargs в коды stdarg, а
       также   возникают   некоторые   проблемы   с   переменными
       функциями,   передающимим   все  свои  аргументы  функции,
       принимающей  аргумент  va_list  (так,  как   это   делает,
       например, vfprintf(3)).




Linux Programmer's Manual   2001-10-14                  STDARG(3)

Документация Linux www.linuxdoc.ru