stringtranslate.com

stdarg.h

stdarg.h— заголовок в стандартной библиотеке C языка программирования C , который позволяет функциям принимать неопределенное количество аргументов . [1] Он предоставляет возможности для пошагового прохождения списка аргументов функции неизвестного количества и типа. C++ предоставляет эту функциональность в заголовке cstdarg.

Содержимое stdarg.hобычно используется в вариативных функциях , хотя оно может использоваться и в других функциях (например, vprintf), вызываемых вариативными функциями.

Объявление вариативных функций

Функции с переменным числом аргументов — это функции, которые могут принимать переменное число аргументов и объявляются с многоточием вместо последнего параметра. Примером такой функции является printf. Типичное объявление:

проверка int ( int a , double b , ...);     

Вариативные функции должны иметь по крайней мере один именованный параметр, например,

символ * неправильный (...); 

не допускается в C17 и более ранних версиях, но в C++ и C23 [2] такое объявление допускается.

В языке C запятая должна предшествовать многоточию, если указан именованный параметр, тогда как в C++ это необязательно.

Определение вариативных функций

Тот же синтаксис используется в определении:

длинная функция ( char , double , int , ...);    длинная функция ( char a , double b , int c , ...) { /* ... */ }        

В определениях функций старого стиля многоточие может отсутствовать.

типы stdarg.h

макросы stdarg.h

Доступ к аргументам

Согласно стандарту, доступ к неименованным аргументам можно получить через переменную типа va_listв вариативной функции, при этом макрос va_startтакже предоставляется в качестве последнего именованного параметра функции. В C23 второй аргумент является необязательным и не будет оцениваться. [2] После этого каждый вызов макроса va_argвозвращает следующий аргумент. Первый аргумент — va_argэто va_list, а второй — тип следующего аргумента, переданного функции. В качестве последнего шага макрос va_endдолжен быть вызван для , va_listпрежде чем функция вернет значение. Обратите внимание, что не требуется считывать все аргументы.

C99 предоставляет дополнительный макрос, va_copy, который может дублировать состояние va_list. Вызов макроса va_copy(va2, va1)копирует va1в va2.

Не существует определенного метода для подсчета или классификации неименованных аргументов, переданных вариативной функции. Функция должна просто определить это каким-то образом, средства чего меняются. Общие соглашения включают:

Передача неименованных аргументов другим вызовам

Поскольку размер неименованного списка аргументов, как правило, неизвестен, соглашения о вызовах, используемые большинством компиляторов, не позволяют определить размер неименованного блока аргументов, на который указывает va_listвнутри принимающей функции. В результате также нет надежного, универсального способа переслать неименованные аргументы в другую вариативную функцию. Даже если определение размера списка аргументов возможно косвенными способами (например, путем анализа строки формата fprintf()), нет переносимого способа передать динамически определенное количество аргументов во внутренний вариативный вызов, поскольку количество и размер аргументов, передаваемых в такие вызовы, как правило, должны быть известны во время компиляции. В некоторой степени это ограничение можно смягчить, используя вариативные макросы вместо вариативных функций. Кроме того, большинство стандартных библиотечных процедур предоставляют vальтернативные версии с префиксом -, которые принимают ссылку на неименованный список аргументов (т. е. инициализированную va_listпеременную) вместо самого неименованного списка аргументов. Например, vfprintf()является альтернативной версией fprintf()ожидания a va_listвместо фактического неименованного списка аргументов. Таким образом, определяемая пользователем вариативная функция может инициализировать va_listпеременную, используя va_startее, и передать ее в соответствующую стандартную библиотечную функцию, фактически передавая неименованный список аргументов по ссылке, а не по значению. Поскольку в C нет надежного способа передавать неименованные списки аргументов по значению, предоставление вариативных функций API без предоставления эквивалентных функций, принимающих va_listвместо этого, считается плохой практикой программирования.

Тип безопасности

Некоторые реализации C предоставляют расширения C, которые позволяют компилятору проверять правильность использования строк формата и сигнальных символов. За исключением этих расширений, компилятор обычно не может проверить, соответствуют ли переданные неименованные аргументы типу, ожидаемому функцией, или преобразовать их в требуемый тип. Поэтому следует проявлять осторожность, чтобы обеспечить корректность в этом отношении, поскольку неопределенное поведение приводит к несовпадению типов. Например, если ожидаемый тип — int *, то нулевой указатель должен быть передан как (int *)NULL. Запись just NULLприведет к аргументу типа либо intили , ни один из которых не является правильным. Еще одно соображение — это повышенияvoid * аргументов по умолчанию, применяемые к неименованным аргументам. A будет автоматически повышен до a . Аналогично, аргументы типов, более узких, чем an , будут повышены до или . Функция, получающая неименованные аргументы, должна ожидать повышенный тип.floatdoubleintintunsigned int

GCC имеет расширение, которое проверяет переданные аргументы:

format(archetype, string-index, first-to-check)

Атрибут format указывает, что функция принимает аргументы printf, scanf, strftimeили strfmonstyle, которые должны быть проверены по типу относительно строки формата. Например, объявление:

extern int my_printf ( void * my_object , const char * my_format , ...) __attribute__ (( format ( printf , 2 , 3 )));            

заставляет компилятор проверять аргументы в вызовах на my_printfсоответствие printfформату стиля string argument my_format.

—  "5.27 Расширения семейства языков C — объявление атрибутов функций" . Получено 03.01.2009 .

Пример

#include <stdio.h> #include <stdarg.h>  /* вывести все аргументы по одному, пока не будет виден отрицательный аргумент;  предполагается, что все аргументы имеют тип int */ 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 ) { аргументы_печати ( 5 , 2 , 14 , 84 , 97 , 15 , -1 , 48 , -1 ); аргументы_печати ( 84 , 51 , -1 , 3 ); аргументы_печати ( -1 ); аргументы_печати ( 1 , -1 ); return 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 ( args , format ); vsnprintf ( buffer , sizeof buffer , format , args ); va_end ( args ); FlushFunnyStream ( buffer ); }        

varargs.h

Устаревшие версии POSIX определили устаревший заголовок varargs.h, который датируется периодом до стандартизации C и обеспечивает функциональность, аналогичную stdarg.h. Этот заголовок не является частью ни ISO C, ни POSIX. Файл, как определено во второй версии Single UNIX Specification , просто содержит всю функциональность C89 stdarg.h, за исключением того, что:

Интерфейс также отличается. printargsНапример, вместо этого можно написать:

#include <stdio.h> #include <varargs.h>  /* Типа "void" нет; используйте неявный возврат int. */ printargs ( arg1 , va_alist ) va_dcl /* здесь нет точки с запятой! */ { va_list ap ; int i ;        va_start ( ap ); /* указан только va_list! */ for ( i = arg1 ; i >= 0 ; i = va_arg ( ap , int )) printf ( "%d " , i ); va_end ( ap ); putchar ( '\n' ); return ; }                 

и называется так же.

varargs.hтребует определений функций старого стиля из-за способа реализации. [3] И наоборот, невозможно смешивать определения функций старого стиля с stdarg.h.

Ссылки

  1. ^ "IEEE Std 1003.1 stdarg.h" . Получено 2009-07-04 .
  2. ^ ab Gilding, Alex; Meneide, JeanHeyd (15.04.2022). "WG14-N2975: Смягчение требований к спискам переменных параметров, v3" (PDF) .
  3. ^ "Единая спецификация UNIX varargs.h" . Получено 2007-08-01 .