Эта статья написана как руководство или путеводитель . ( Октябрь 2013 г. ) ( Узнайте, как и когда удалить этот шаблон сообщения ) |
Стандартная библиотека C |
---|
Общие темы |
Разные заголовки |
stdarg.h
является заголовком в стандартной библиотеке C на языке программирования C , что позволяет функции принимать неограниченное количество аргументов . [1] Он предоставляет возможности для пошагового просмотра списка аргументов функции неизвестного числа и типа. C ++ предоставляет эту функцию в заголовке cstdarg
.
Содержимое stdarg.h
обычно используется в функциях с переменным числом аргументов , хотя оно может использоваться в других функциях (например, vprintf
), вызываемых функциями с переменным числом аргументов.
Объявление вариативных функций [ править ]
Функции с переменным числом аргументов - это функции, которые могут принимать переменное количество аргументов и объявляются с многоточием вместо последнего параметра. Пример такой функции printf
. Типичное заявление
проверка int ( int a , double b , ...);
Функции с переменным числом аргументов должны иметь хотя бы один именованный параметр, поэтому, например,
char * неправильно (...);
не разрешено в C. (В C ++ такое объявление разрешено). В C запятая должна предшествовать многоточию; в C ++ это необязательно.
Определение вариативных функций [ править ]
Тот же синтаксис используется в определении:
длинная функция ( char , double , int , ...);long func ( char a , double b , int c , ...) { / * ... * / }
Многоточие может не отображаться в определениях функций в старом стиле.
stdarg.h типы [ править ]
Имя | Описание | Совместимость |
---|---|---|
va_list | тип для итерации аргументов | C89 |
макросы stdarg.h [ править ]
Имя | Описание | совместимость |
---|---|---|
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
-подобной строки со встроенными спецификаторами, указывающими типы аргументов. - Контрольное значение в конце вариативных аргументов.
- Аргумент count, указывающий количество аргументов с переменным числом аргументов.
Передача безымянных аргументов другим вызовам [ править ]
Поскольку размер безымянного списка аргументов обычно неизвестен (соглашения о вызовах, используемые большинством компиляторов, не позволяют определять размер безымянного блока аргументов, на который указывает 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
. Точно так же аргументы типов, более узких, чем an, 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>/ * выводим все аргументы по одному, пока не будет обнаружен отрицательный аргумент; предполагается, что все аргументы имеют тип 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 1584 511
Чтобы вызвать другие функции var args из вашей функции (например, sprintf), вам необходимо использовать версию функции var arg (vsprintf в этом примере):
void MyPrintf ( const char * format , ...) { va_list args ; буфер символов [ BUFSIZ ]; va_start ( аргументы , формат ); vsnprintf ( буфер , размер буфера , формат , аргументы ); va_end ( аргументы ); FlushFunnyStream ( буфер ); }
varargs.h [ править ]
Устаревшие версии POSIX определили устаревший заголовок varargs.h
, который появился еще до стандартизации C и обеспечивает функциональность, аналогичную stdarg.h
. Этот заголовок не входит ни в ISO C, ни в POSIX. Файл, как определено во второй версии Единой спецификации UNIX , просто содержит все функциональные возможности C89 stdarg.h
, за исключением следующих: он не может использоваться в стандартных определениях нового стиля C; вы можете отказаться от заданного аргумента (стандарт C требует, по крайней мере, одного аргумента); и то, как это работает, отличается - в стандартном C можно было бы написать:
#include <stdarg.h>int 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
функцией будет:
#include <varargs.h>summate ( 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
требует определения функций в старом стиле из-за того, как работает реализация. [2] И наоборот, нельзя смешивать определения функций в старом стиле с stdarg.h
.
Ссылки [ править ]
- ^ "IEEE Std 1003.1 " . Проверено 4 июля 2009 .stdarg.h
- ^ «Единая спецификация UNIX » . Проверено 1 августа 2007 .varargs.h