printf

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

printf (отангл. print formatted, «форматированная печать») — обобщённое название семействафункций илиметодовстандартных или широко известных коммерческих библиотек, или встроенных операторов некоторыхязыков программирования, используемых дляформатного вывода — вывода в различныепотоки значений разныхтипов, отформатированных согласно заданному шаблону. Этот шаблон определяется составленной по специальным правилам строкой (форматной строкой).

Наиболее ярким представителем этого семейства является функцияprintf, а также ряд других функций с производными отprintf названиями в стандартной библиотеке языкаСи (являющейся также частью стандартной библиотекиСи++ иObjective-C).

В операционных системах семействаUNIX имеется также утилитаprintf, служащая тем же целям форматного вывода.

Ранним прототипом такой функции можно считать операторFORMAT языкаФортран. Функция вывода, управляемая строкой, появилась в предшественниках языка Си (BCPL иБи). В спецификациистандартной библиотеки языка Си она получила свой наиболее известный вид (с флагами, шириной, точностью и размером). Синтаксис строки шаблона вывода (называемой иногдастрокой форматирования,строкой формата илиформатной строкой) в дальнейшем начал использоваться и другими языками программирования (с вариациями ради приспособления к особенностям этих языков). Как правило, соответствующие функции этих языков также носят названиеprintf и/или производные от него.

Некоторые более поздние среды программирования (например,.NET) также используют концепцию вывода, управляемого форматной строкой, но с иным синтаксисом.

Содержание

История

[править |править код]

Появление

[править |править код]

УжеФортран I имел операторы, обеспечивавшие форматный вывод. Синтаксис операторовWRITE иPRINT предусматривал метку, отсылающую к неисполняемому операторуFORMAT, который содержал форматную спецификацию. Спецификаторы были частью синтаксиса оператора, и компилятор сразу мог сформировать код, непосредственно выполняющий форматирование данных, что обеспечивало наилучшую производительность на вычислительных машинах тех времён. Однако имелись следующие недостатки:

  • Усложнение без того запутанного синтаксиса языка.
  • Форматную спецификацию невозможно было сформировать в ходе исполнения программы.
  • Форматная спецификация была текстуально отделена от оператора вывода, что было неудобно для сопровождения программ.

Первый прототип будущей функцииprintf появляется в языкеBCPL в1960-х. ФункцияWRITEF принимает строку форматирования, в которойтип данных указывается отдельно от самих данных встроковой переменной (тип указывался без полей флагов, ширины, точности и размера, но уже предварялся символом процента%).[1] Основной целью появления строки форматирования была передача типов аргументов (в языках программирования состатической типизацией определение типа переданного аргумента для функции с нефиксированным списком формальных параметров требует сложного и неэффективного для общего случая механизма передачи информации о типах). Сама функцияWRITEF была средством упрощения вывода: вместо наборафункцийWRCH (вывод символа),WRITES (вывод строки),WRITEN,WRITED,WRITEOCT,WRITEHEX (вывод чисел в различной форме) использовался единый вызов, в котором можно было чередовать «просто текст» с выходными значениями.

Появившийся вслед за ним в1969 году языкБи уже использовал названиеprintf с простейшей строкой форматирования (аналогичнойBCPL), указывался только один из трёх возможных типов и два представления числа: десятичные (%d), восьмеричные (%o), строки (%s) и символы (%c), а единственной возможностью по форматированию вывода в этих функциях было добавление символов до и после вывода значения переменной.[2]

Си и производные

[править |править код]

С момента появления первого варианта языка Си (1970) семействоprintf стало основным средством форматного вывода. Затраты на разбор форматной строки при каждом вызове функции были сочтены приемлемыми, и альтернативные вызовы для каждого типа в отдельности в библиотеку введены не были. Спецификация функции вошла в оба существующихстандарта языка, вышедших в1990 и1999 годах. Спецификация 1999 года содержит некоторые нововведения по отношению к спецификации 1990 года.

ЯзыкСи++ использует стандартную библиотеку Си (в соответствии со стандартом 1990 года), в том числе и всё семействоprintf.

В качестве альтернативы стандартная библиотека Си++ предложила набор классов потокового ввода и вывода. Операторы вывода этой библиотеки типобезопасны и не требуют разбора форматных строк при каждом вызове. Тем не менее, многие программисты продолжают пользоваться семействомprintf, так как запись последовательности вывода с ними обычно оказывается компактнее, а суть применяемого формата — яснее.

Objective-C является довольно «тонкой» надстройкой над Си, и программы на нём могут напрямую пользоваться функциями семействаprintf.

Использование в других языках программирования

[править |править код]

Помимо Си и его производных (Си++, Objective-C), printf-подобный синтаксис строки форматирования используют многие другие языки программирования:

  • Perl —sprintf[3];
  • Python — форматирующий оператор%[4] и функцияstr.format;
  • PHP — функцияprintf[5];
  • Java — функцияjava.io.PrintStream.printf[6];
  • Ruby — функцияprintf[7];
  • Lua — функцияstring.format[8];
  • TCL — функцияformat[9];
  • GNU Octave — функцияprintf[10];
  • Maple — функцияprintf (встроенный язык)[11];
  • AMPL[12];
  • Elisp (format string &rest objects)[13];
  • OCaml — функцияprintf[14];
  • Haskell — функцияprintf[15];
  • Rust — макрос println![16];
  • Pascal — функция Format[17].
  • Go — функция fmt.Printf (fmt.Sprintf для вывода в строку)[18]

Помимо этого, благодаря наличию утилитыprintf в составе большинства UNIX-подобных систем,printf используется во многих shell-скриптах (дляsh,bash,csh,zsh и т. д.).

Последователи

[править |править код]

Некоторые более поздние языки и среды программирования также используют концепцию вывода управляемого форматной строкой, но с иным синтаксисом.

Например, в основной библиотеке классов (FCL) среды.Net имеется семейство методовSystem.String.Format,System.Console.Write иSystem.Console.WriteLine, некоторыеперегрузки которых выполняют вывод своих данных в соответствии с форматной строкой. Так как в среде исполнения .Net доступна полная информация о типах объектов, необходимости передавать эту информацию в форматной строке нет.

Именование функций семейства

[править |править код]

Все функции имеют в имени основуprintf. Префиксы перед именем функции означают:

  • v (vprintf,vsnprintf и т. д.) — функция вместо переменного числа параметров принимает параметр типаva_list, хранящий произвольное количество аргументов.
  • f (fprintf,vfprintf) — вывод результата в передаваемый через параметр функциипоток, вместо стандартного вывода.
  • s (sprintf,snprintf,vsprintf,vsnprintf) — запись результата в строку (буфер в памяти), а не поток.
  • n (snprintf,vsnprintf) — наличие параметра, ограничивающего максимальное количество символов для записи результата (используется только вместе с префиксомs). В Maple функцияnprintf аналогичнаsprintf, но возвращает не текстовую строку, а имя.
  • w, перед остальными префиксами (wsprintf,wvsprintf,wnsprintf,wvnsprintf) — использующийся фирмойMicrosoft префикс для реализаций семейства функцийsprintf в операционных системахWindows.
  • w, после остальных префиксов (fwprintf,swprintf,wprintf) — функция использует строки из«широких» символов (wchar_t) вместо обычных строк. (при этом функцияswprintf не имеет префикса «n», хотя и принимает параметр, ограничивающий размер результирующей строки).
  • a (asprintf,vasprintf) — расширенияGNU; функции, аналогичные sprintf/vsprintf, но выделяющие достаточный объём памяти с помощьюmalloc для форматированной строки. Вместо указателя на строку эти функции принимаютуказатель на указатель на строку, освобождение памяти производит вызвавшая функция.

Общие соглашения

[править |править код]

Все функции в качестве одного из параметров (format) принимаютстроку форматирования (описаниесинтаксиса строки ниже). Возвращают количество записанных (выведенных) символов, не включаянулевой символ в конце. Количество аргументов, содержащих данные для форматированного вывода, должно быть не менее, чем упомянуто в строке форматирования. «Лишние» аргументы игнорируются.

Функции семействаn (snprintf,vsnprintf) возвращают количество символов, которое было бы выведено, если бы параметрn (ограничивающий количество выводимых символов) был достаточно большим. В случае однобайтовыхкодировок возвращаемое значение соответствует необходимому размеру строки (не включая нулевой символ в конце).

Функции семействаs (sprintf,snprintf,vsprintf,vsnprintf) первым параметром (s) принимают указатель на область памяти, куда будет записана результирующая строка. Функции, не имеющие ограничения по количеству записываемых символов, являютсянебезопасными функциями, так как могут привести к ошибкепереполнения буфера, в случае, если выводимая строка окажется больше, чем размер выделенной для вывода области памяти.

Функции семействаf записывают строку в любой открытый поток (параметрstream), в частности, в стандартные потоки вывода (stdout,stderr).fprintf(stdout, format, …) эквивалентноprintf(format, …).

Функции семействаv принимают аргументы не в виде переменного числа аргументов (как все остальные printf-функции), а в виде спискаva list. При этом при вызове функции макросva end не выполняется.

Функции семействаw (первым символом) являются ограниченной реализацией Microsoft семейства функцийs:wsprintf,wnsprintf,wvsprintf,wvnsprintf. Эти функции реализованы в динамических библиотекахuser32.dll иshlwapi.dll (n функции). Они не поддерживают вывод значений с плавающей запятой, кроме того,wnsprintf иwvnsprintf поддерживают выравнивание текста только по левому краю.

Функции семействаw (wprintf,swprintf) реализуют поддержку многобайтовых кодировок, все функции этого семейства работают с указателями на многобайтные строки (wchar_t).

Функции семействаa (asprintf,vasprintf) выделяют память для строки вывода при помощи функцииmalloc, освобождение памяти производится в вызвавшей процедуре, в случае ошибки при выполнении функции память не выделяется.

Описание функций

[править |править код]

Имена параметров

[править |править код]
  • format — строка форматирования (формат описан ниже)
  • stream — файловый поток для вывода
  • s — строка для помещения результата работы функции
  • n — переменная, содержащая максимальное допустимое количество символов для строкиs
  • ap — список значений для вывода
  • strp — указатель на указатель на строку для помещения результатов работы функции

Описание функций

[править |править код]
  • int printf( const char *format, ... );
    Вывод форматированной строки на стандартный вывод
  • int fprintf( FILE *stream, const char *format, ... );
    Вывод форматированной строки в поток
  • int sprintf( char *s, const char *format, ... );
    Запись форматированной строки в строку без ограничения по размеру строки
  • int snprintf( char *s, size_t n, const char *format, ... );
    Запись форматированной строки в строку с ограничением по размеру строки
  • int vprintf( const char *format, va_list ap );
    Вывод форматированной строки на стандартный вывод, значения для вывода передаются в функцию в виде спискаva list
  • int vfprintf( FILE *stream, const char *format, va_list ap );
    Запись форматированной строки в поток, значения для вывода передаются в функцию в виде спискаva list
  • int vsprintf( char *s, const char *format, va_list ap );
    Запись форматированной строки в строку без ограничения размера; значения для вывода передаются в функцию в виде спискаva list
  • int vsnprintf( char *s, size_t n, const char *format, va_list ap );
    Запись форматированной строки в строку с ограничением на количество выводимых символов. Значения для вывода передаются в функцию в виде спискаva list
  • int fwprintf(FILE *stream, const wchar_t *format, ... );
    Запись форматированной строки многобайтовых символов в файл
  • int swprintf(wchar_t *ws, size_t n, const wchar_t *format, ... );
    Запись форматированной многобайтовой строки в область памяти (Примечание: несмотря на отсутствие буквыn в названии, эта функция принимает параметр, ограничивающий максимальный размер выходной строки).
  • int wprintf(const wchar_t *format, ... );
    Вывод многобайтовой форматированной строки на терминал
  • int wsprintf( LPTSTR s, LPCTSTR format, ... );
    Реализация функцииsprintf в операционной системеWindows. В отличие от sprintf, не поддерживает вывод значений с плавающей запятой, вывод указателей, дополнительно поддерживает обработку многобайтовых строк в однобайтовой версии функции), не поддерживает флаг '+'.
  • int wnsprintf( LPTSTR s, int n, LPCTSTR format, ... );
    Реализация функцииsnprintf в операционной системеWindows. Не поддерживает вывод значений с плавающей запятой и указателей, поддерживает только флаг выравнивания по левому краю.
  • int wvsprintf( LPTSTR s, LPCTSTR format, va_list ap );
  • int wvnsprintf( LPTSTR s, int n, LPCTSTR format, va_list ap );
  • int asprintf(char **strp, const char *format, ... );
    функция записывает результат в строку, память для которой выделяется при помощиmalloc
  • int vasprintf(char **strp, const char *format, va_list ap);
    функция записывает результат в строку, память для которой выделяется при помощиmalloc, значения для вывода передаются в функцию в виде спискаva list

Возвращаемое значение: отрицательное значение — признак ошибки; в случае успеха функции возвращают количество записанных/выведенных байтов (без учёта нулевого байта в конце), функцияsnprintf выводит количество байт, которые были бы записаны, если быn было достаточного размера.

При вызовеsnprintf,n может быть равно нулю (в этом случаеs может бытьнулевым указателем), в этом случае запись не производится, функция только возвращает правильное возвращаемое значение.

Синтаксис строки форматирования

[править |править код]
Пример вызова printf с комментариями

В языке Си и Си++ строка форматирования представляет собой строку, завершённую нулевым символом. Все символы, кроме спецификаторов формата, копируются в итоговую строку без изменений. Стандартным признаком начала спецификатора формата является символ% (Знак процента), для вывода самого знака% используется его удвоение%%.

Структура спецификатора формата

[править |править код]

Спецификатор формата имеет вид:

%[флаги][ширина][.точность][размер]тип

Обязательными составными частями являются символ начала спецификатора формата (%) итип.

Флаги

[править |править код]
ЗнакНазвание знакаЗначениеВ отсутствие этого знакаПримечание
-минусвыводимое значение выравнивается по левому краю в пределах минимальной ширины поляпо правому
+плюсвсегда указывать знак (плюс или минус) для выводимого десятичного числового значениятолько для отрицательных чисел
 пробелпомещать перед результатом пробел, если первый символ значения не знакВывод может начинаться с цифры.Символ+ имеет больший приоритет, чем пробел. Используется только для знаковых десятичных значений.
#решётка«альтернативная форма» вывода значенияПри выводе чисел в шестнадцатеричном или восьмеричном форматах перед числом будет указываться особенность формата (0x или 0 соответственно).
0нольдополнять поле до ширины, указанной в полеширина управляющей последовательности, символом0дополнять пробеламиИспользуется для типовd,i,o,u,x,X,a,A,e,E,f,F,g,G. Для типовd,i,o,u,x,X, еслиточность указана, этот флаг игнорируется. Для остальных типов поведение не определено.

Если указан флаг минус '-', этот флаг так же игнорируется.

Модификатор ширины

[править |править код]

Ширина (десятичное число или символзвёздочка) указывает минимальную ширину поля (включая знак для чисел). Если представление величины больше, чем ширина поля, то запись выходит за пределы поля (например,%2i для величины 100 даст значение поля в три символа), если представление величины менее указанного числа, то оно будет дополнено (по умолчанию) пробелами слева, поведение может меняться в зависимости от других заданных флагов. Если в качестве ширины указана звёздочка, ширина поля указывается в списке аргументов перед значением для вывода (например,printf( "%0*x", 8, 15 ); выведет текст0000000f). Если этим способом указан отрицательный модификатор ширины, считается что выставленфлаг-, а значение модификатора ширины установлено абсолютным.

Модификатор точности

[править |править код]
  • указывает на минимальное количество символов, которое должно появиться при обработке типовd,i,o,u,x,X;
  • указывает на минимальное количество символов, которое должно появиться после десятичной запятой (точки) при обработке типовa,A,e,E,f,F;
  • максимальное количество значащих символов для типовg иG;
  • максимальное число символов, которые будут выведены для типаs;

Точность задаётся в виде точки с последующим десятичным числом или звёздочкой (*), если число или звёздочка отсутствует (присутствует только точка), то предполагается, что число равно нулю. Точка для указания точности используется даже в том случае, если при выводе чисел с плавающей запятой выводится запятая.

Если после точки указан символ «звёздочка», то при обработке строки форматирования значение для поля читается из списка аргументов. (При этом, если символ звёздочка и в поле ширины и в поле точности, сначала указывается ширина, потом точность и лишь потом значение для вывода). Например,printf( "%0*.*f", 8, 4, 2.5 ); выведет текст002.5000. Если этим способом указан отрицательный модификатор точности, то считается, что модификатор точности отсутствует.[19]

Модификатор размера

[править |править код]

Полеразмер позволяет указать размер данных, переданных функции. Необходимость в этом поле объясняется особенностями передачи произвольного количества параметров в функцию в языке Си: функция не может «самостоятельно» определить тип и размер переданных данных, так что информация о типе параметров и точном их размере должна передаваться явно.

Рассматривая влияние размерных спецификаций на форматирование целочисленных данных, нужно отметить, что в языках Си и Си++ имеется цепочка пар знаковых и беззнаковых целых типов, которые в порядке неубывания размеров располагаются так:

Знаковый типБеззнаковый тип
signed charunsigned char
signed short (short)unsigned short int (unsigned short)
signed int (int)unsigned int (unsigned)
signed long int (long)unsigned long int (unsigned long)
signed long long int (long long)unsigned long long int (unsigned long long)

Точные размеры типов неизвестны, за исключением типовsigned char иunsigned char.

Парные знаковый и беззнаковый типы имеют одинаковый размер, а значения, представимые в обоих типах, имеют в них одинаковое представление.

Типchar имеет одинаковый размер с типамиsigned char иunsigned char и общий набор представимых значений с одним из этих типов. Далее считается, чтоchar — другое имя одного из этих типов; такое допущение приемлемо для настоящего рассмотрения.

Кроме того, в языке Си присутствует тип_Bool, а в Си++ —bool.

При передаче в функцию аргументов, которым не соответствуют формальные параметры в прототипе функции (а таковыми являются все аргументы, содержащие выводимые значения), эти аргументы подвергаютсястандартным продвижениям, а именно:

  • аргументы типаfloat приводятся к типуdouble;
  • аргументы типовunsigned char,unsigned short,signed char иshort приводятся к одному из следующих типов:
    • int, если этот тип способен представить все значения исходного типа, или
    • unsigned в противном случае;
  • аргументы типов_Bool илиbool приводятся к типуint.

Для краткости изложения ниже для обозначения типа результата стандартного продвижения типаT используется нотацияPROMOTED(T).

Таким образом, функции printf не могут получать аргументов типовfloat,_Bool илиbool или целочисленных типов, меньших, чемint илиunsigned.

Набор применяемых спецификаторов размера зависит от спецификатора типа (см. ниже).

Спецификатор%d,%i%o,%u,%x,%X%nПримечание
отсутствуетintunsigned intуказатель наint
llong intunsigned long intуказатель наlong int
hhАргумент имеет типPROMOTED(signed char), но принудительно приводится к типуsigned charАргумент имеет типPROMOTED(unsigned char), но принудительно приводится к типуunsigned charуказатель наsigned char

Формально существуют в языке Си начиная со стандарта от 1999 года, а в языке Си++ — начиная со стандарта от 2011 года.

В некоторых случаях компиляторы и среды программирования, выпущенные до издания соответствующих стандартов, занимают эти спецификаторы для других целей. Вместо этого они могут предоставлять другие спецификаторы.

hАргумент имеет типPROMOTED(short int), но принудительно приводится к типуshort intАргумент имеет типPROMOTED(unsigned short int), но принудительно приводится к типуunsigned short intуказатель наshort int
lllong long intunsigned long long intуказатель наlong long int
jintmax_tuintmax_tуказатель наintmax_t
zэквивалентный по размеруsize_t знаковый типsize_tуказатель на эквивалентный по размеруsize_t знаковый тип (sic!)
tptrdiff_tэквивалентный по размеруptrdiff_t беззнаковый типуказатель наptrdiff_t

Спецификацииh иhh используются для компенсации стандартных продвижений типов в сочетании с переходами от знаковых типов к беззнаковым, или наоборот.

Например, рассмотрим реализацию Си, где типchar знаковый и имеет размер 8 бит, типint имеет размер 32 бит, используется дополнительный способ кодирования отрицательных целых.

charc=255;printf("%X",c);

Такой вызов даст выводFFFFFFFF, что, возможно, не то, чего ожидал программист. Действительно, значениеc равно(char)(-1), а после продвижения типа оно оказывается равно-1. Применение формата%X вызывает интерпретацию данного значения как беззнакового, то есть0xFFFFFFFF.

charc=255;printf("%X",(unsignedchar)c);
charc=255;printf("%hhX",c);

Эти два вызова имеют один и тот же эффект и дают выводFF. Первый вариант позволяет избежать размножения знака при продвижении типа, второй — компенсирует его уже «внутри» функцииprintf.

Спецификатор%a,%A,%e,%E,%f,%F,%g,%G
отсутствуетdouble
Llong double
Спецификатор%c%s
отсутствуетАргумент имеет типint илиunsigned int, но принудительно приводится к типуcharchar*
lАргумент имеет типwint_t, но принудительно приводится к типуwchar_twchar_t*

Спецификатор типа

[править |править код]

Тип указывает не только на тип величины (с точки зрения языка программирования Си), но и на конкретное представление выводимой величины (например, числа могут выводить в десятичном или шестнадцатеричном виде). Записывается в виде одного символа. В отличие от остальных полей, является обязательным. Максимальный поддерживаемый размер вывода от единичной управляющей последовательности составляет по стандартам как минимум 4095 символов; на практике большинство компиляторов поддерживают существенно большие объёмы данных.

Значения типов:

  • d,i — десятичное знаковое число, тип по умолчаниюint. По умолчанию записывается с правым выравниванием, знак пишется только для отрицательных чисел. В отличие от функций семействаscanf, для функций семействаprintf спецификации%d и%i полностью синонимичны;
  • o — восьмеричное беззнаковое число, тип по умолчаниюunsigned int;
  • u — десятичное беззнаковое число, тип по умолчаниюunsigned int;
  • x иX — шестнадцатеричное беззнаковое число,x использует маленькие буквы (abcdef),X большие (ABCDEF), тип по умолчаниюunsigned int;
  • f иF — числа с плавающей запятой, тип по умолчаниюdouble. По умолчанию выводятся с точностью 6, если число по модулю меньше единицы, перед десятичной точкой пишется 0. Величины±∞ представляются в форме[-]inf или[-]infinity (в зависимости от платформы); величинаNan представляется как[-]nan или[-]nan(любой текст далее). ИспользованиеF выводит указанные величины заглавными буквами ([-]INF,[-]INFINITY,NAN).
  • e иE — числа с плавающей запятой вэкспоненциальной форме записи (вида 1.1e+44), тип по умолчаниюdouble.e выводит символ «e» в нижнем регистре,E — в верхнем (3.14E+0);
  • g иG — число с плавающей запятой, тип по умолчаниюdouble. Форма представления зависит от значения величины (f илиe). Формат немного отличается от числа с плавающей запятой тем, что незначащие нули справа от запятой не выводятся. Также часть с запятой не отображается, если число целое;
  • a иA (начиная со стандартов языка Си от 1999 года и Си++ от 2011 года) — число с плавающей запятой в шестнадцатеричном виде, тип по умолчаниюdouble;
  • c — вывод символа с кодом, соответствующим переданному аргументу, тип по умолчаниюint;
  • s — выводстроки с нулевым завершающим байтом; если модификатор длины —l, выводится строкаwchar_t*. ВWindows значения типаs зависят от типа используемых функций. Если используется семействоprintf функций, тоs обозначает строкуchar*. Если используется семействоwprintf функций, тоs обозначает строкуwchar_t*.
  • S — то же самое, что иs с модификатором длиныl; ВWindows значения типаS зависит от типа используемых функций. Если используется семействоprintf функций, тоS обозначает строкуwchar_t*. Если используется семействоwprintf функций, тоS обозначает строкуchar*.
  • p — выводуказателя, внешний вид может существенно различаться в зависимости от внутреннего представления в компиляторе и платформе (например, 16-битная платформа MS-DOS использует форму записи видаFFEC:1003, 32-битная платформа сплоской адресацией использует адрес вида00FA0030);
  • n — запись по указателю, переданному в качестве аргумента, количества символов, записанных на момент появления командной последовательности, содержащейn;
  • % — символ для вывода знака процента (%), используется для возможности вывода символов процента в строке printf, всегда используется в виде%%.
Вывод чисел с плавающей запятой
[править |править код]

В зависимости от текущейлокали, при выводе чисел с плавающей запятой может использоваться как запятая, так и точка (а, возможно, и другой символ). Поведениеprintf в отношении разделяющего дробную и целую часть числа символа определяется использующейсялокалью (точнее, переменнойLC NUMERIC).[20]

Специальные макросы для расширенного набора псевдонимов целочисленных типов данных

[править |править код]

Второй стандарт языка Си (1999) предусматривает расширенный набор псевдонимов целочисленных типов данныхintN_t,uintN_t,int_leastN_t,uint_leastN_t,int_fastN_t,uint_fastN_t (гдеN — требуемая разрядность),intptr_t,uintptr_t,intmax_t,uintmax_t.

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

int64_tx=100000000000;intwidth=20;printf("%0*lli",width,x);
Неправильно, так как типint64_t может не совпадать с типомlong long int.

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

Имена макросов имеют следующий вид:

Пара знакового и беззнакового типовИмя макроса
intN_t иuintN_tPRITN
int_leastN_t иuint_leastN_tPRITLEASTN
int_fastN_t иuint_fastN_tPRITFASTN
intmax_t иuintmax_tPRITMAX
intptr_t иuintptr_tPRITPTR

ЗдесьT — одна из следующих спецификаций типа:d,i,u,o,x,X.

int64_tx=100000000000;intwidth=20;printf("%0*"PRIi64,width,x);
Правильный способ вывода значения типаint64_t в языке Си.

Можно заметить, что для типовintmax_t иuintmax_t имеется стандартный спецификатор размераj, поэтому макросPRITMAX, скорее всего, всегда определён как"jT".

XSI-расширения в стандарте Single Unix

[править |править код]

В рамках стандартаSingle UNIX (практически эквивалентного стандартуPOSIX), определены следующие дополнения printf по отношению к ISO C, в рамках расширенияXSI (X/Open System Interface):

  • Добавляется возможность вывода произвольного по номеру параметра (указывается в видеn$ сразу после символа начала управляющей последовательности, например,printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);).
  • Добавлен флаг «'» (одинарная кавычка), который для типовd,i,o,u предписывает разделятьклассы соответствующим символом.
  • типC, эквивалентныйlc ISO C (вывод символа типаwint_t).
  • типS, эквивалентныйls ISO C (вывод строки типаwchar_t*)
  • Добавлены коды ошибок EILSEQ, EINVAL, ENOMEM, EOVERFLOW.

Нестандартные расширения

[править |править код]

GNU C Library

[править |править код]

В рамках GNU C Library (libc) добавлены следующие расширения:

  • типm выводит значение глобальной переменнойerrno (код ошибки последней функции).
  • типC эквивалентенlc.
  • флаг' (одинарная кавычка) используется для разделения классов при выводе чисел. Формат разделения зависит отLC_NUMERIC
  • размерq указывает на типlong long int (на системах, где не поддерживается типlong long int, это то же самое, что иlong int
  • размерZ является псевдонимом дляz, был введён в libc до появления стандартаC99, не рекомендуется к использованию в новом коде.
Регистрация собственных типов
[править |править код]

GNU libc поддерживает регистрацию пользовательских типов, позволяя программисту определять формат вывода для собственных структур данных. Для регистрации новоготипа используется функция
int register_printf_function (int type, printf_function handler-function, printf_arginfo_function arginfo-function), где:

  • type — буква для типа (если type = 'Y', то вызов будет выглядеть как '%Y');
  • handler-function — указатель на функцию, которая вызывается printf-функциями, если в строке форматирования встречается тип, указанный вtype;
  • arginfo-function — указатель на функцию, которая будет вызываться функциейparse_printf_format.

Помимо определения новых типов, регистрация позволяет переопределить существующие типы (такие, какs,i).

Microsoft Visual C

[править |править код]

В составе MicrosoftVisual Studio для языков программирования Си/Си++ в формате спецификации printf (и остальных функций семейства) предусмотрены следующие расширения:

  • поле размера:
значение полятип
I32signed __int32,unsigned __int32
I64signed __int64,unsigned __int64
Iptrdiff_t,size_t
wэквивалентноl для строк и символов

Maple

[править |править код]

В среде математических вычисленийMaple также имеется функция printf, она имеет следующие особенности:

Форматирование
[править |править код]
    • %a, %A: объект Maple будет выдан в текстовой нотации, это работает для всех объектов (например, матриц, функций, модулей и т. д.). Строчная буква предписывает окружать обратными апострофами символы (имена), которые должны быть окружены ими на входе printf.
    • %q, %Q: то же, что и %a/%A, но обрабатываться будет не один аргумент, а все начиная с того, которому соответствует флаг форматирования. Таким образом, флаг %Q/%q может стоять только последним в строке формата.
    • %m: форматировать объект в соответствии с его внутренним для Maple представлением. Практически используется для записи переменных в файл.

Пример:

> printf("%a =%A", `+`, `+`);`+` = +
> printf("%a =%m", `+`, `+`);`+` = I"+f*6"F$6#%(builtinGF$"$Q"F$F$F$F"%*protectedG
Вывод
[править |править код]

Функция fprintf в maple в первом аргументе принимает либо дескриптор файла (возвращаемый функцией fopen), либо имя файла. В последнем случае имя должно иметь тип «символ», если имя файла содержит точки, то его обязательно нужно заключить в обратные апострофы или преобразовать функцией convert (имя_файла, symbol).

Уязвимости

[править |править код]

Функции семействаprintf принимают список аргументов и их размер отдельным параметром (в строке форматирования). Несоответствие строки форматирования и переданных аргументов может приводить к непредсказуемому поведению, повреждению стека и выполнению произвольного кода, приводить к разрушению областей динамической памяти. Многие функции семейства называются «небезопасными» (англ. unsafe), так как не имеют даже теоретической возможности для защиты от некорректных данных.

Также функции семействаs (безn, такие какsprintf,vsprintf) не имеют ограничителей по максимальному размеру записываемой строки и могут приводить к ошибкепереполнения буфера (когда данные записываются за пределы отведённой области памяти).

Поведение при несоответствии строки форматирования и переданных аргументов

[править |править код]
Стек при правильном вызове printf

В рамкахсоглашения о вызовеcdecl, очисткустека осуществляет вызвавшая функция. При вызовеprintf аргументы (или указатели на них) помещаются в порядке следования записи (слева направо). По мере обработки строки форматирования функцияprintf читает аргументы со стека. Возможны следующие ситуации:

  • количество и тип аргументов совпадают с указанными в строке форматирования (нормальная работа функции)
  • в функцию передано больше аргументов, чем указано в строке форматирования (лишние аргументы)
  • в функцию передано меньше аргументов, чем требуется согласно строке форматирования (недостаток аргументов)
  • в функцию переданы аргументы неправильного размера
  • в функцию переданы аргументы правильного размера, но неправильного типа

Спецификации языка Си описывают только две ситуации (нормальной работы и лишних аргументов). Все остальные ситуации являются ошибочными и приводят кнеопределённому поведению программы (в реальности приводящему к произвольным результатам, вплоть до выполнения незапланированных участков кода).

Избыточное количество аргументов

[править |править код]

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

Недостаточное количество аргументов

[править |править код]

Если при вызовеprintf аргументов в стеке меньше, чем требуется для обработки строки форматирования, то недостающие аргументы читаются со стека, несмотря на то, что на стеке находятся произвольные данные (не имеющие отношения к работеprintf). Если обработка данных прошла «успешно» (то есть не привела к прекращению работы программы, зависанию или записи в стек), после возврата в вызывающую функцию значение указателя стека возвращается в исходное, и работа программы продолжается.

При обработке «лишних» значений стека возможны следующие ситуации:

  • Успешное чтение «лишнего» параметра для вывода (число, указатель, символ и т. д.) — в результаты вывода помещается «почти случайное» значение, прочитанное со стека. Это не представляет собой опасности для работы программы, но может приводить ккомпрометации каких-либо данных (вывод значений стека, которые может использовать злоумышленник для анализа работы программы и получению доступа к внутренней/закрытой информации программы).
  • Ошибка при чтении значения со стека (например, в результате исчерпания доступных значений стека или доступ к «несуществующим» страницам памяти) — такая ошибка, вероятнее всего, приведёт к аварийному завершению работы программы.
  • Чтение указателя на параметр. Строки передаются с помощью указателя, при чтении «произвольной» информации со стека, прочитанное (почти случайное) значение используется как указатель на случайную область памяти. Поведение программы в этом случае не определено и зависит от содержимого этой области памяти.
  • Запись параметра по указателю (%n) — в данном случае поведение аналогично ситуации с чтением, но осложняется возможнымисторонними эффектами записи в произвольную ячейку памяти.

Несоответствие типов аргументов

[править |править код]

Формально любое несоответствие типа аргумента ожиданию вызывает неопределённое поведение программы. На практике можно выделить несколько особо интересных с точки зрения программистской практики случаев:

  • Аргумент имеет тот же тип, что и ожидается, но другой размер.
  • Аргумент имеет тот же размер, что и ожидается, но другой тип.

Иные случаи, как правило, приводят к очевидно некорректному поведению, и легко выявляются.

Несоответствие размера целочисленного аргумента или аргумента с плавающей точкой

[править |править код]

Для целочисленного аргумента (при целочисленной же форматной спецификации) возможны следующие ситуации:

  • Передача параметров, размер которых больше ожидаемого (чтение меньшего из большего). При этом, в зависимости от принятого порядка байтов и направления роста стека, выведенное значение может как совпасть со значением аргумента, так и оказаться не имеющим к нему отношения.
  • Передача параметров, размер которых меньше ожидаемого (чтение большего из меньшего). В этом случае возможна ситуация, когда читаются области стека, выходящие за пределы переданных аргументов. Поведение функции в этом случае аналогично поведению в ситуации с недостатком параметров. В общем случае выводимое значение не соответствует ожидаемому.

Для вещественного аргумента (при вещественной же форматной спецификации) при любом несовпадении размеров выводимое значение, как правило, не совпадает с переданным.

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

Выравнивание значений на стеке
[править |править код]

На многих платформах действуют правила выравнивания целочисленных и/или вещественных значений, требующие (или рекомендующие) их размещения по адресам, кратным их размеру. Эти правила распространяются и на передачу аргументов функций через стек. В этом случае ряд несовпадений типов ожидаемых и фактических параметров может оставаться незамеченным, создавая иллюзию правильности программы.

uint32_ta=1;uint64_tb=2,c=3;printf("%"PRId64"%"PRId64"%"PRId64,b,a,c);
В данном примере фактическому параметруa типаuint32_t сопоставлена неверная форматная спецификация%"PRId64", предусмотренная для типаuint64_t. Тем не менее, на ряде платформ c 32-разрядным типомint, в зависимости от принятого порядка байт и направления роста стека, ошибка может оставаться незамеченной. Фактические параметрыb иc будут выровнены по адресу, кратному их размеру (вдвое больше размераa). А «между» значениямиa иb будет оставлено пустое (как правило, занулённое) пространство размером в 32 бита; при обработке спецификации%"PRId64" 32-разрядное значениеa вместе с этим пустым пространством будут истолкованы как единое 64-разрядное значение.

Подобная ошибка может неожиданно проявиться при переносе программного кода на другую платформу, смене компилятора или режима компиляции.

Потенциальное несоответствие размеров
[править |править код]

Определения языков Си и Си++ описывают лишь наиболее общие требования к размерам и представлению типов данных. Поэтому на многих платформах представление некоторых формально разных типов данных оказываются одинаковыми. Это приводит к тому, что некоторые несовпадения типов могут долгое время оставаться необнаруженными.

Например, на платформе Win32 общепринято, что размеры типовint иlong int совпадают (32 разряда). Так, вызовprintf("%ld", 1) илиprintf("%d", 1L) будет выполнен «правильно».

Подобная ошибка может неожиданно проявиться при переносе программного кода на другую платформу, смене компилятора или режима компиляции.

При написании программ на языке Си++ нужно внимательно относиться к выводу значений переменных, объявленных при помощи псевдонимов целочисленных типов, в частностиsize_t иptrdiff_t; формальное определение стандартной библиотеки Си++ ссылается на первый стандарт языка Си (1990). Во втором стандарте языка Си (1999) для типовsize_t иptrdiff_t и для ряда иных типов определены спецификаторы размера для использования с подобными объектами. Многие реализации Си++ их также поддерживают.

size_ts=1;printf("%u",s);
Данный пример содержит ошибку, способную проявиться на платформах, гдеsizeof (unsigned int) не равноsizeof (size_t).
size_ts=1;printf("%zu",s);
Правильный способ вывести значение объекта типаsize_t в языке Си.

Несоответствие типов при совпадении размеров

[править |править код]

Если переданные аргументы совпадают по размеру, но имеют отличный тип, то часто работа программы будет «почти правильной» (не вызовет ошибок доступа к памяти), хотя выводимое значение, вероятнее всего, будет бессмысленным. Надо отметить, что смешение па́рных друг другу целочисленных типов (знакового и беззнакового) допустимо, неопределённого поведения не вызывает, и иногда сознательно используется в практике.

При использовании форматной спецификации%s значение аргумента целочисленного, вещественного типа или типа указателя иного, нежелиchar*, будет проинтерпретировано как адрес строки. Этот адрес, вообще говоря, может произвольно указывать на несуществующую или недоступную область памяти, что приведёт к ошибке доступа к памяти, либо на область памяти, не содержащую строки, что приведёт к выводу бессмыслицы, возможно, очень объёмному.

Уязвимость строки форматирования

[править |править код]

Так какprintf (и остальные функции семейства) могут выводить текст строки форматирования без изменений, если он не содержит управляющих последовательностей, то возможен вывод текста командой
printf(text_to_print);
В случае, еслиtext_to_print получается из внешних источников (читается из файла, получается от пользователя или операционной системы), то наличие в получаемой строке знака процента может приводить к крайне нежелательным последствиям (вплоть до зависания программы).

Пример некорректного кода:
printf(" Current status: 99% stored.");
В этом примере содержится управляющая последовательность«% s», содержащая признак управляющей последовательности (%), флаг (пробел) и тип данных «строка» (s). Функция, приняв управляющую последовательность, попытается прочитать из стека указатель на строку. Так как функции не передавались дополнительные параметры, значение, которое будет прочитано со стека, не определено. Полученное значение будет интерпретировано как указатель на строку с завершающим нулём. Вывод такой «строки» может привести к выводу произвольного дампа памяти, ошибке доступа к памяти и разрушению стека. Такой тип уязвимости называютатакой на строку форматирования (англ. Format string attack).[21]

Переполнение буфера

[править |править код]

Функцияprintf при выводе результата не ограничивается по максимальному количеству выводимых символов. Если в результате ошибки или недосмотра будет выведено больше символов, чем ожидалось, худшее, что может случиться — это «разрушение» картинки на экране. Созданная по аналогии сprintf функцияsprintf также не ограничивалась в максимальном размере результирующей строки. Однако, в отличие от «бесконечного» терминала, память, которую выделяет приложение для результирующей строки, всегда ограничена. И в случае выхода за ожидаемые рамки запись производится в области памяти, принадлежащие другим структурам данных (или, вообще, в недоступные участки памяти, что практически на всех платформах означает аварийное завершение программы). Запись в произвольные области памяти приводит к непредсказуемым эффектам (которые, возможно, проявятся много позже и не в форме ошибки программы, а в форме повреждения пользовательских данных). Отсутствие ограничения на максимальный размер строки является принципиальной ошибкой планирования при разработке функции. Именно из-за этого функцииsprintf иvsprintf имеют статуснебезопасных. Взамен им были разработаны функцииsnprintf,vsnprintf, принимающие дополнительный аргумент, ограничивающий максимальную результирующую строку. Появившаяся много позже функцияswprintf (для работы с многобайтными кодировками) учитывает эту недоработку и принимает аргумент для ограничения результирующей строки. (Именно поэтому нет функцииsnwprintf).

Пример опасного вызоваsprintf:

char buffer[65536];char* name = get_user_name_from_keyboard();sprintf(buffer, "User name:%s", name);

В вышеприведённом коде неявно предполагается, что пользователь не будет печатать 65 тысяч символов на клавиатуре, и буфера «должно хватить». Но пользователь может перенаправить ввод из другой программы или всё-таки ввести более 65 тысяч символов. В этом случае произойдёт повреждение областей памяти и поведение программы станет непредсказуемым.

Сложности в использовании

[править |править код]

Отсутствие контроля типов

[править |править код]

Функции семействаprintf используют типы данных языкаСи. Размеры этих типов и их соотношения могут меняться от платформы к платформе. Например, на 64-битных платформах в зависимости от выбранной модели (LP64,LLP64 илиILP64) размеры типовint иlong могут различаться. Если программист задаст форматную строку «почти правильно», код будет работать на одной платформе и выдавать неправильный результат на другой (в ряде случаев, возможно, приводя к повреждению данных).

Например, кодprintf( "text address: 0x%X", "text line" ); работает правильно на 32-битной платформе (размерptrdiff_t и размерint 32 бита) и на 64-битной модели IPL64 (где размерыptrdiff_t иint 64 бита), но даст неверный результат на 64-битной платформе модели LP64 или LLP64, где размерptrdiff_t 64 бита, а размерint 32 бита.[22]

ВOracle Java в аналоге функцииprintf применяютсяобёрнутые типы сдинамической идентификацией,[6] вEmbarcadero Delphi — промежуточная прослойкаarray of const,[23] в различных реализациях наC++[24] —перегрузка операций, вC++20 — вариативные шаблоны. К тому же форматы (%d,%f и т. д.) задают не тип аргумента, а лишь формат вывода, так что замена типа аргумента может вызватьаварийную ситуацию или нарушить высокоуровневую логику (например, «сломать» вёрстку таблицы) — но не испортить память.

Недостаточная стандартизация

[править |править код]

Проблема усугубляется недостаточной стандартизацией форматных строк в разных компиляторах: например, ранние версии библиотек Microsoft не поддерживали"%lld" (приходилось указывать"%I64d"). Всё ещё есть разделение между Microsoft и GNU по типуsize_t:%Iu у первого и%zu у второго. GNU C не требует в функцииswprintf максимальную длину строки (приходится писатьsnwprintf).

Невозможность переставить аргументы местами

[править |править код]

Функции семействаprintf удобны длялокализации программного обеспечения: например, проще перевести«You hit %s instead of %s.», чем обрывки строк«You hit »,« instead of » и«.». Но и здесь таится проблема: невозможно переставить подставляемые строки местами, чтобы получилось:«Вы попали не в <2>, а в <1>.».

Расширенияprintf, применяемые вOracle Java иEmbarcadero Delphi, всё-таки позволяют переставить аргументы местами.

Утилита printf

[править |править код]

В рамках стандартаPOSIX описана утилитаprintf, которая форматирует аргументы по соответствующему шаблону, аналогично функцииprintf.

Утилита имеет следующий формат вызова:printfformat [argument …], где

  • format — строка формата, по синтаксису похожая на строку формата функцииprintf.
  • argument — список аргументов (0 или более), записанных в строковой форме.

Примеры реализации

[править |править код]

Пример 1Си (язык программирования)

[править |править код]
#include<stdio.h>#include<locale.h>#define PI 3.141593intmain(){setlocale(LC_ALL,"RUS");intnumber=7;floatpies=12.75;intcost=7800;printf("%d участников соревнований съели %f пирожков с вишнями.\n",number,pies);printf("Значение pi равно %f\n",PI);printf("До свидания! Ваше искусство слишком дорого обходится (%c%d)\n",'$',2*cost);return0;}

Пример 2Си (язык программирования)

[править |править код]
#include<stdio.h>#define PAGES 959intmain(){printf("*%d*\n",PAGES);printf("*%2d*\n",PAGES);printf("*%10d*\n",PAGES);printf("*%-10d*\n",PAGES);return0;}/*Результат:*959**959**       959**959       **/

Пример 3Си (язык программирования)

[править |править код]
#include<stdio.h>#define BLURB "Authentic imitation!"intmain(){constdoubleRENT=3852.99;printf("*%8f*\n",RENT);printf("*%e*\n",RENT);printf("*%4.2f*\n",RENT);printf("*%3.1f*\n",RENT);printf("*%10.3f*\n",RENT);printf("*%10.3E*\n",RENT);printf("*%+4.2f*\n",RENT);printf("%x %X %#x\n",31,31,31);printf("**%d**% d% d **\n",42,42,-42);printf("**%5d**%5.3d**%05d**%05.3d**\n",6,6,6,6);printf("\n");printf("[%2s]\n",BLURB);printf("[%24s]\n",BLURB);printf("[%24.5s]\n",BLURB);printf("[%-24.5s]\n",BLURB);return0;}/* результат*3852.990000**3.852990e+03**3852.99**3853.0**  3852.990** 3.853E+03**+3852.99*1f 1F 0x1f**42** 42-42 ****    6**  006**00006**  006**[Authentic imitation!][    Authentic imitation!][                   Authe][Authe                   ]*/

Ссылки

[править |править код]
  1. Краткое описание языка BCPL . Дата обращения: 16 декабря 2006. Архивировано 9 декабря 2006 года.
  2. Руководство по языку БиАрхивировано 6 июля 2006 года.
  3. Описание функцииsprintf в документации Perl . Дата обращения: 12 января 2007. Архивировано 14 января 2007 года.
  4. Описание форматирующего оператора для строковых типов в ПитонеАрхивировано 9 ноября 2006 года.
  5. Описание функцииprintf в составе PHP . Дата обращения: 23 октября 2006. Архивировано 6 ноября 2006 года.
  6. 12Описание функцииjava.io.PrintStream.printf() в Java 1.5 . Дата обращения: 12 января 2007. Архивировано 13 января 2007 года.
  7. Описание функцииprintf в документации Ruby . Дата обращения: 3 декабря 2006. Архивировано 5 декабря 2006 года.
  8. Описание функцииstring.format в документации Lua . Дата обращения: 14 января 2010. Архивировано 15 ноября 2013 года.
  9. Описание функцииformat в документации TCL . Дата обращения: 14 апреля 2008. Архивировано 4 июля 2007 года.
  10. Описание шаблона строки дляprintf в документации GNU Octave . Дата обращения: 3 декабря 2006. Архивировано 27 октября 2006 года.
  11. Документация Maple . Дата обращения: 12 декабря 2023. Архивировано 23 июля 2023 года.
  12. R. Fourer, D.M. Gay, and B.W. Kernighan. AMPL: A Modeling Language for Mathematical Programming, 2nd Ed.. Pacific Grove, CA: Brooks/Cole--Thomson Learning, 2003.
  13. GNU Emacs Lisp Reference Manual,Formatting StringsАрхивная копия от 27 сентября 2007 наWayback Machine
  14. Описание модуляPrintf в документации OCaml . Дата обращения: 12 января 2007. Архивировано 13 января 2007 года.
  15. Описание модуляPrintf в документации Haskell . Дата обращения: 23 июня 2015. Архивировано 23 июня 2015 года.
  16. std::println! - Rust . doc.rust-lang.org. Дата обращения: 24 июля 2016. Архивировано 18 августа 2016 года.
  17. Format . www.freepascal.org. Дата обращения: 7 декабря 2016. Архивировано 24 ноября 2016 года.
  18. fmt - The Go Programming Language . golang.org. Дата обращения: 25 марта 2020. Архивировано 4 апреля 2020 года.
  19. §7.19.6.1 ISO/IEC 9899:TC2
  20. § 7.11.1.1 ISO/IEC 9899:TC2,LC_NUMERIC определяет, в частности, форму представления разделителя дробной и целой части.
  21. Описание уязвимостей printf, Robert C. Seacord: Secure Coding in C and C++. Addison Wesley, September, 2005.ISBN 0-321-33572-4
  22. Описание проблем переноса приложений с 32 на 64 битную архитектуру . Дата обращения: 14 декабря 2006. Архивировано 8 марта 2007 года.
  23. System.SysUtils.FormatАрхивная копия от 11 января 2013 наWayback Machine (англ.)
  24. Например,boost::format,документацияАрхивная копия от 26 марта 2013 наWayback Machine (англ.)

Источники

[править |править код]
  • printf,fprintf,snprintf,vfprintf,vprintf,vsnprintf,vsprintf в стандарте ISO/IEC 9899:TC2 (ISO C)[3]
  • printf,fprintf,sprintf,snprintf в стандартеSingle Unix[4]
  • vprintf,vfprintf,vsprintf,vsnprintf в стандартеPOSIX[5]
  • wprintf,swprintf,wprintf в стандартеPOSIX[6]
  • vfwprintf,vswprintf,vwprintf в стандартеPOSIX[7]
  • wsprintf вMSDN[8]
  • wvnsprintf в MSDN[9]
  • wnsprintf в MSDN[10]
  • wvsprintf в MSDN[11]
  • wnsprintf в MSDN[12]
  • asprintf,vasprintf вman-pages в Linux[13], в документации кlibc[14]
  • Описание синтаксиса строки форматирования в руководствеlibc[15].
  • Описание строки форматирования в документации к MicrosoftVisual Studio 2005[16]
  • Описаниеregister_printf_function[17],[18]
  • Язык программирования C. Лекции и упражнения. Автор: Стивен Прата.ISBN 978-5-8459-1950-2 , 978-0-321-92842-9; 2015 г.

См. также

[править |править код]
Перейти к шаблону «Команды Unix»
Команды Unix
Перейти к шаблону «POSIX.1-2008»
УтилитыPOSIX.1-2008
Источник —https://ru.wikipedia.org/w/index.php?title=Printf&oldid=149826164
Категории:
Скрытые категории: