stdarg.h
- это заголовок в стандартной библиотеке C файла Язык программирования C, который позволяет функциям принимать неопределенное количество аргументов. Он предоставляет возможности для пошагового просмотра списка аргументов функции неизвестного числа и типа. C ++ предоставляет эту функциональность в заголовке cstdarg
.
Содержимое stdarg.h
обычно используется в вариационных функциях, хотя их можно использовать в других функциях (например, vprintf
), вызываемых вариативными функциями.
Функции с переменным числом - это функции, которые могут принимать переменное количество аргументов и являются объявлен с многоточием вместо последнего параметра. Пример такой функции - printf
. Типичное объявление -
int check (int a, double b,...);
Функции с переменными числами должны иметь хотя бы один именованный параметр, например,
char * error (...);
не допускается в C. (В C ++ такое объявление разрешено). В C запятая должна предшествовать многоточию; в C ++ это необязательно.
В определении используется тот же синтаксис:
long func (char, double, int,...); long func (char a, double b, int c,...) {/ *... * /}
Многоточие может не отображаться в определениях функций в старом стиле.
Name | Описание | Compatibility |
---|---|---|
va_list | тип для итерации аргументов | C89 |
Имя | Описание | совместимость |
---|---|---|
va_start | Начать итерацию аргументов с va_list | C89 |
va_arg | Получить аргумент | C89 |
va_end | Освободить va_list | C89 |
va_copy | Копировать содержимое одного va_list в другой | C99 |
Для доступа к безымянным аргументам необходимо объявить переменную типа va_list
в вариативной функции. Затем вызывается макрос va_start
с двумя аргументами: первый - это переменная, объявленная с типом va_list
, вторая - это имя последнего указанного параметра функции. После этого каждый вызов макроса va_arg
дает следующий аргумент. Первый аргумент va_arg
- это va_list
, а второй - тип следующего аргумента, переданного функции. Наконец, перед возвратом функции должен быть вызван макрос va_end
в va_list
. (Не требуется читать все аргументы.)
C99 предоставляет дополнительный макрос, va_copy
, который может дублировать состояние va_list
. Вызов макроса va_copy (va2, va1)
копирует va1
в va2
.
. Не определен механизм для определения количества или типов безымянных аргументов, переданных в функцию.. Функция просто обязана каким-то образом знать или определять это, средства для этого могут быть разными. Общие соглашения включают:
printf
или scanf
со встроенными спецификаторами, указывающими типы аргументов. 140>контрольное значение в конце вариативных аргументов.Поскольку размер безымянный список аргументов обычно неизвестен (соглашения о вызовах, используемые большинством компиляторов, не позволяют определять размер безымянного блока аргументов, на который указывает va_list
внутри принимающей функции), также нет надежного универсального способа для пересылки безымянных аргументов в другую вариативную функцию. Даже если определение размера списка аргументов возможно косвенными средствами (например, путем анализа строки формата fprintf ()
), нет переносимого способа передать динамически определяемое количество аргументов в внутренний вариативный вызов, поскольку количество и размер аргументов, передаваемых в такие вызовы, обычно должны быть известны во время компиляции. В некоторой степени это ограничение можно ослабить, используя макросы с переменными числами вместо функций с переменными числами. Кроме того, большинство стандартных библиотечных процедур предоставляют альтернативные версии с префиксом v
, которые принимают ссылку на безымянный список аргументов (то есть на инициализированную переменную va_list
) вместо самого безымянного списка аргументов. Например, vfprintf ()
- это альтернативная версия fprintf ()
, ожидающая va_list
вместо фактического безымянного списка аргументов. Поэтому определяемая пользователем вариационная функция может инициализировать переменную va_list
с помощью va_start
и передать ее соответствующей стандартной библиотечной функции, фактически передавая безымянный список аргументов по ссылке вместо того, чтобы делать это с помощью значение. Поскольку в C не существует надежного способа передачи безымянных списков аргументов по значению, предоставление функций с переменным числом аргументов API без предоставления эквивалентных функций, принимающих вместо этого va_list
, считается плохой практикой программирования.
Некоторые реализации C предоставляют расширения C, которые позволяют компилятору проверять правильность использования строк формата и контрольных индикаторов. Запрещая эти расширения, компилятор обычно не может проверить, соответствуют ли переданные безымянные аргументы ожидаемому функцией типу, или преобразовать их в требуемый тип. Следовательно, следует позаботиться о том, чтобы гарантировать правильность в этом отношении, поскольку неопределенное поведение возникает, если типы не совпадают. Например, если ожидаемый тип - int *
, тогда нулевой указатель должен быть передан как (int *) NULL
. Запись только NULL
приведет к аргументу типа int
или void *
, ни один из которых не является правильным. Еще одно соображение - аргумент по умолчанию promotions, применяемый к безымянным аргументам. float
будет автоматически преобразован в double
. Аналогичным образом, аргументы типов, меньших, чем int
, будут преобразованы в int
или unsigned int
. Функция, получающая безымянные аргументы, должна ожидать повышенный тип.
GCC имеет расширение, которое проверяет переданные аргументы:
формат (архетип, строковый индекс, первая проверка)
Атрибут формата указывает, что функция принимает printf
, scanf
, strftime
или strfmon
аргументы стиля, которые должны проверяться на соответствие типу строки формата. Например, объявление:
extern int my_printf (void * my_object, const char * my_format,...) __attribute__ ((format (printf, 2, 3)));
заставляет компилятор проверять аргументы в вызовах my_printf
на согласованность с аргументом строки формата стиля printf
my_format
.
#include#include / * выводит все аргументы по одному, пока не будет обнаружен отрицательный аргумент; предполагается, что все аргументы имеют тип int * / void printargs (int arg1,...) {va_list ap; int i; va_start (ap, arg1); для (я = arg1; я>= 0; я = va_arg (ap, int)) printf ("% d", я); va_end (ap); путчар ('\ п'); } int main (void) {printargs (5, 2, 14, 84, 97, 15, -1, 48, -1); printargs (84, 51, -1, 3); printargs (-1); printargs (1, -1); возврат 0; }
Эта программа дает результат:
5 2 14 84 97 15 84 51 1
Чтобы вызвать другие функции var args из вашей функции (например, sprintf), вам необходимо использовать версия функции var arg (в данном примере vsprintf):
void MyPrintf (const char * format,...) {va_list args; буфер символов [BUFSIZ]; va_start (аргументы, формат); vsnprintf (буфер, размер буфера, формат, аргументы); va_end (аргументы); FlushFunnyStream (буфер); }
Устаревшие версии POSIX определили унаследованный заголовок varargs.h
, который появился еще до стандартизации C и обеспечивает функциональность, аналогичную stdarg.h
. Этот заголовок не входит ни в ISO C, ни в POSIX. Файл, как определено во второй версии Single UNIX Specification, просто содержит все функциональные возможности C89 stdarg.h
, за исключением следующих: он не может использоваться в стандартных Определения нового стиля C; вы можете отказаться от заданного аргумента (стандартный C требует хотя бы одного аргумента); и способ его работы отличается - в стандартном C можно было бы написать:
#includeint summate (int n,...) {va_list ap; int я = 0; va_start (ap, n); для (; n; n--) i + = va_arg (ap, int); va_end (ap); вернуть я; }
и вызовите с
summate (0); summate (1, 2); summate (4, 9, 2, 3, 2);
Для varargs.h
функция будет выглядеть так:
#includesummate (n, va_alist) va_dcl / * точки с запятой здесь нет! * / {va_list ap; int я = 0; va_start (ap); для (; n; n--) i + = va_arg (ap, int); va_end (ap); вернуть я; }
и называется так же.
varargs.h
требует определения функций в старом стиле из-за того, как работает реализация. И наоборот, нельзя смешивать определения функций в старом стиле с stdarg.h
.