Provided by: manpages-ru-dev_4.18.1-1_all bug

ИМЯ

       stdarg,  va_start,  va_arg,  va_end,  va_copy  -  работа со списком переменного количества
       аргументов

LIBRARY

       Standard C library (libc, -lc)

СИНТАКСИС

       #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_copy()  копирует  (ранее  инициализированный)  список  с переменным количеством
       аргументов src в dest. Его действие такое же, как если бы va_start() применили  к  dest  с
       тем же аргументом last, после чего было бы совершено такое же количество вызовов va_arg(),
       которое имеется в текущем состоянии src.

       Очевидной реализацией было бы создать переменную с типом 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 — имя, которое использовалось в
       черновике стандарта.

АТРИБУТЫ

       Описание терминов данного раздела смотрите в attributes(7).

       ┌────────────────────────────────────────────────┬──────────────────────┬─────────────────┐
       │ИнтерфейсАтрибутЗначение        │
       ├────────────────────────────────────────────────┼──────────────────────┼─────────────────┤
       │va_start(), va_end(), va_copy()                 │ Безвредность в нитях │ MT-Safe         │
       ├────────────────────────────────────────────────┼──────────────────────┼─────────────────┤
       │va_arg()                                        │ Безвредность в нитях │ MT-Safe race:ap │
       └────────────────────────────────────────────────┴──────────────────────┴─────────────────┘

СТАНДАРТЫ

       C99.

ДЕФЕКТЫ

       В отличие от исторических макросов varargs,  макросы  stdarg  не  позволяют  программистам
       создать  функцию  без  постоянных аргументов. Эта проблема создаёт работу, в основном, при
       преобразовании кода varargs в код stdarg, а также есть сложности с функциями с  переменным
       количеством аргументов, которым нужно передать все их аргументы в функцию в виде аргумента
       с типом va_list, например vfprintf(3).

ПРИМЕРЫ

       Функция foo берёт строку с символами формата и печатает аргумент, связанный с каждым таким
       символом, на основе его типа.

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

       void
       foo(char *fmt, ...)   /* '...' is C syntax for a variadic function */

       {
           va_list ap;
           int d;
           char c;
           char *s;

           va_start(ap, fmt);
           while (*fmt)
               switch (*fmt++) {
               case 's':              /* string */
                   s = va_arg(ap, char *);
                   printf("string %s\n", s);
                   break;
               case 'd':              /* int */
                   d = va_arg(ap, int);
                   printf("int %d\n", d);
                   break;
               case 'c':              /* char */
                   /* need a cast here since va_arg only
                      takes fully promoted types */
                   c = (char) va_arg(ap, int);
                   printf("char %c\n", c);
                   break;
               }
           va_end(ap);
       }

СМ. ТАКЖЕ

       vprintf(3), vscanf(3), vsyslog(3)

ПЕРЕВОД

       Русский    перевод    этой    страницы    руководства   был   сделан   Alexander   Golubev
       <fatzer2@gmail.com>,  Azamat  Hackimov  <azamat.hackimov@gmail.com>,   Hotellook,   Nikita
       <zxcvbnm3230@mail.ru>,       Spiros       Georgaras       <sng@hellug.gr>,       Vladislav
       <ivladislavefimov@gmail.com>,   Yuri   Kozlov   <yuray@komyakino.ru>   и    Иван    Павлов
       <pavia00@gmail.com>

       Этот  перевод  является  бесплатной  документацией;  прочитайте  Стандартную  общественную
       лицензию GNU версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если  вы  обнаружите  ошибки  в  переводе этой страницы руководства, пожалуйста, отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.