stdarg.h
Эта статья написана как руководство или руководство . ( октябрь 2013 г. ) |
Стандартная библиотека C (libc) |
---|
Общие темы |
Разные заголовки |
|
stdarg.h
— это заголовок в стандартной библиотеке C языка программирования C , который позволяет функциям принимать неопределенное количество аргументов . [ 1 ] Он предоставляет возможности для пошагового просмотра списка аргументов функции неизвестного числа и типа. C++ предоставляет эту функциональность в заголовке. cstdarg
.
Содержание stdarg.h
обычно используются в вариативных функциях , хотя могут использоваться и в других функциях (например, vprintf
), вызываемый вариативными функциями.
Объявление вариативных функций
[ редактировать ]Вариатические функции — это функции, которые могут принимать переменное количество аргументов и объявляются с многоточием вместо последнего параметра. Примером такой функции является printf
. Типичное заявление
int check(int a, double b, ...);
Вариадные функции должны иметь хотя бы один именованный параметр, например:
char *wrong(...);
не разрешено в C17 и более ранних версиях. (В C++ C23 и [ 2 ] такое объявление разрешено.) В C запятая должна предшествовать многоточию, если указан именованный параметр; в C++ это необязательно.
Определение вариативных функций
[ редактировать ]Тот же синтаксис используется в определении:
long func(char, double, int, ...);
long func(char a, double b, int c, ...)
{
/* ... */
}
Многоточие может не отображаться в определениях функций старого стиля.
типы stdarg.h
[ редактировать ]Имя | Описание | Совместимость |
---|---|---|
va_list |
тип для итерации аргументов | С89 |
макросы stdarg.h
[ редактировать ]Имя | Описание | совместимость |
---|---|---|
va_start |
Начните перебор аргументов с помощью va_list |
С89 |
va_arg |
Получить аргумент | С89 |
va_end |
Бесплатно va_list |
С89 |
va_copy |
Скопируйте содержимое одного va_list другому |
С99 |
Доступ к аргументам
[ редактировать ]Чтобы получить доступ к безымянным аргументам, необходимо объявить переменную типа va_list
в вариатической функции. Макрос va_start
затем вызывается с двумя аргументами: первый — это переменная, объявленная типа va_list
, второй — имя последнего именованного параметра функции. В C23 второй аргумент будет необязательным и не будет оцениваться. [ 2 ] После этого каждый вызов va_arg
макрос возвращает следующий аргумент. Первый аргумент для va_arg
это va_list
а второй — тип следующего аргумента, передаваемого функции. Наконец, va_end
макрос должен вызываться va_list
прежде чем функция вернется. (Не обязательно читать все аргументы.)
C99 предоставляет дополнительный макрос, va_copy
, который может дублировать состояние va_list
. Вызов макроса va_copy(va2, va1)
копии va1
в va2
.
Не существует определенного метода подсчета или классификации безымянных аргументов, передаваемых функции. Функция просто обязана это каким-то образом знать или определить, средства для чего различаются. Общие конвенции включают в себя:
- Использование
printf
илиscanf
-подобная строка формата со встроенными спецификаторами, указывающими типы аргументов. - Контрольное значение в конце переменных аргументов.
- Аргумент-счетчик, указывающий количество аргументов с переменным числом аргументов.
Передача безымянных аргументов другим вызовам
[ редактировать ]Поскольку размер списка безымянных аргументов обычно неизвестен (соглашения о вызовах, используемые большинством компиляторов, не позволяют определить размер блока безымянных аргументов, на который указывает 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 *
, ни то, ни другое неверно. Еще одним соображением являются повышения аргументов по умолчанию, применяемые к безымянным аргументам. А float
будет автоматически повышен до double
. Аналогично, аргументы типов, более узких, чем int
будет повышен до int
или unsigned int
. Функция, получающая безымянные аргументы, должна ожидать расширенного типа.
GCC имеет расширение, которое проверяет переданные аргументы:
format(archetype, string-index, first-to-check)
Атрибут формата указывает, что функция принимает
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
.— «5.27 Расширения семейства языков C — объявление атрибутов функций» . Проверено 3 января 2009 г.
Пример
[ редактировать ]#include <stdio.h>
#include <stdarg.h>
/* print all args one at a time until a negative argument is seen;
all args are assumed to be of int type */
void printargs(int arg1, ...)
{
va_list ap;
int i;
va_start(ap, arg1);
for (i = arg1; i >= 0; i = va_arg(ap, int))
printf("%d ", i);
va_end(ap);
putchar('\n');
}
int main(void)
{
printargs(5, 2, 14, 84, 97, 15, -1, 48, -1);
printargs(84, 51, -1, 3);
printargs(-1);
printargs(1, -1);
return 0;
}
Эта программа дает результат:
5 2 14 84 97 15 84 51 1
Чтобы вызвать другие функции с переменными аргументами из вашей функции (например, sprintf), вам необходимо использовать версию функции с переменными аргументами (в этом примере vsprintf):
void MyPrintf(const char *format, ...)
{
va_list args;
char buffer[BUFSIZ];
va_start(args, format);
vsnprintf(buffer, sizeof buffer, format, args);
va_end(args);
FlushFunnyStream(buffer);
}
varargs.h
[ редактировать ]Устаревшие версии POSIX определяли устаревший заголовок. varargs.h
, который появился еще до стандартизации C и обеспечивает функциональность, аналогичную stdarg.h
. Этот заголовок не является частью ни ISO C, ни POSIX. Файл, как определено во второй версии Единой спецификации UNIX , просто содержит все функциональные возможности C89. stdarg.h
, за исключением того, что:
- его нельзя использовать в стандартных определениях нового стиля C.
- данный аргумент может быть опущен (стандарт C требует хотя бы один аргумент)
Интерфейс также отличается. Для printargs
например, вместо этого можно было бы написать:
#include <stdio.h>
#include <varargs.h>
/* There is no "void" type; use an implicit int return. */
printargs(arg1, va_alist)
va_dcl /* no semicolon here! */
{
va_list ap;
int i;
va_start(ap); /* only the va_list is given! */
for (i = arg1; i >= 0; i = va_arg(ap, int))
printf("%d ", i);
va_end(ap);
putchar('\n');
return;
}
и называется так же.
varargs.h
требует определений функций в старом стиле из-за особенностей работы реализации. [ 3 ] И наоборот, невозможно смешивать определения функций старого стиля с stdarg.h
.
Ссылки
[ редактировать ]- ^ «IEEE стандарт 1003.1
stdarg.h
" Проверено 4 июля 2009 г. . - ^ Перейти обратно: а б Позолота, Алекс; Менейд, Жан Хейд (15 апреля 2022 г.). «WG14-N2975: Ослабьте требования к спискам переменных параметров, версия 3» (PDF) .
- ^ «Единая спецификация UNIX
varargs.h
" Проверено 1 августа 2007 г. .