Provided by: manpages-ru-dev_4.23.1-1_all 

ИМЯ
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 │
└──────────────────────────────────────────────────────────────┴──────────────────────┴─────────────────┘
СТАНДАРТЫ
C11, POSIX.1-2008.
ИСТОРИЯ
va_start()
va_arg()
va_end()
C89, POSIX.1-2001.
va_copy()
C99, POSIX.1-2001.
CAVEATS
В отличие от исторических макросов 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 (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или
более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом
разработчику по его адресу электронной почты или по адресу списка рассылки русских переводчиков.
Linux man-pages 6.8 2 мая 2024 г. stdarg(3)