Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

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 типы [ править ]

макросы stdarg.h [ править ]

Доступ к аргументам [ править ]

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

Ссылки [ править ]

  1. ^ "IEEE Std 1003.1 " . Проверено 4 июля 2009 .stdarg.h
  2. ^ «Единая спецификация UNIX » . Проверено 1 августа 2007 .varargs.h