printf (от , «форматированная печать») — обобщённое название семейства функций, выводящих отформатированные согласно строке форматирования данные. Строка форматирования может содержать спецификаторы, обозначающие правила форматирования, такие как выравнивание или округление, и, в ряде случаев, тип данных. В своём стандартном виде выводит данные в терминал, однако существуют и вариации, записывающие результат в файл или другую строку.
Ранним прототипом такой функции можно считать оператор FORMAT языка Фортран. Функция вывода, управляемая строкой, появилась в предшественниках языка Си (BCPL и Би). В спецификации стандартной библиотеки языка Си она получила свой наиболее известный вид (с флагами, шириной, точностью и размером). Синтаксис строки шаблона вывода (называемой иногда строкой форматирования, строкой формата или форматной строкой) в дальнейшем начал использоваться и другими языками программирования (с вариациями ради приспособления к особенностям этих языков). Как правило, соответствующие функции этих языков также носят название printf или производные от него.
История
Появление Уже Фортран I имел операторы, обеспечивавшие форматный вывод. Синтаксис операторов WRITE и PRINT предусматривал метку, отсылающую к неисполняемому оператору FORMAT, который содержал форматную спецификацию. Спецификаторы были частью синтаксиса оператора, и компилятор сразу мог сформировать код, непосредственно выполняющий форматирование данных, что обеспечивало наилучшую производительность на вычислительных машинах тех времён. Однако имелись следующие недостатки:
Усложнение без того запутанного синтаксиса языка. Форматную спецификацию невозможно было сформировать в ходе исполнения программы. Форматная спецификация была текстуально отделена от оператора вывода, что было неудобно для сопровождения программ.
Первый прототип будущей функции printf появляется в языке BCPL в 1960-х. Функция WRITEF принимает строку форматирования, в которой тип данных указывается отдельно от самих данных в строковой переменной (тип указывался без полей флагов, ширины, точности и размера, но уже предварялся символом процента %). Основной целью появления строки форматирования была передача типов аргументов (в языках программирования со статической типизацией определение типа переданного аргумента для функции с нефиксированным списком формальных параметров требует сложного и неэффективного для общего случая механизма передачи информации о типах). Сама функция WRITEF была средством упрощения вывода: вместо набора функций WRCH (вывод символа), WRITES (вывод строки), WRITEN, WRITED, WRITEOCT, WRITEHEX (вывод чисел в различной форме) использовался единый вызов, в котором можно было чередовать «просто текст» с выходными значениями.
Появившийся вслед за ним в 1969 году язык Би уже использовал название printf с простейшей строкой форматирования (аналогичной BCPL), указывался только один из трёх возможных типов и два представления числа: десятичные (%d), восьмеричные (%o), строки (%s) и символы (%c), а единственной возможностью по форматированию вывода в этих функциях было добавление символов до и после вывода значения переменной.Руководство по языку Би
Си и производные С момента появления первого варианта языка Си (1970) семейство printf стало основным средством форматного вывода. Затраты на разбор форматной строки при каждом вызове функции были сочтены приемлемыми, и альтернативные вызовы для каждого типа в отдельности в библиотеку введены не были. Спецификация функции вошла в оба существующих стандарта языка, вышедших в 1990 и 1999 годах. Спецификация 1999 года содержит некоторые нововведения по отношению к спецификации 1990 года.
Язык Си++ использует стандартную библиотеку Си (в соответствии со стандартом 1990 года), в том числе и всё семейство printf.
В качестве альтернативы стандартная библиотека Си++ предложила набор классов потокового ввода и вывода. Операторы вывода этой библиотеки типобезопасны и не требуют разбора форматных строк при каждом вызове. Тем не менее, многие программисты продолжают пользоваться семейством printf, так как запись последовательности вывода с ними обычно оказывается компактнее, а суть применяемого формата — яснее.
Objective-C является довольно «тонкой» надстройкой над Си, и программы на нём могут напрямую пользоваться функциями семейства printf.
Использование в других языках программирования Помимо Си и его производных (Си++, Objective-C), printf-подобный синтаксис строки форматирования используют многие другие языки программирования: Perl — sprintf; Python — форматирующий оператор %Описание форматирующего оператора для строковых типов в Питоне и функция str.format; PHP — функция printf; Java — функция java.io.PrintStream.printf; Ruby — функция printf; Lua — функция string.format; TCL — функция format; GNU Octave — функция printf; Maple — функция printf (встроенный язык); AMPLR. 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.; Elisp (format string &rest objects)GNU Emacs Lisp Reference Manual, Formatting Strings ; OCaml — функция printf; Haskell — функция printf; Rust — макрос println!; Pascal — функция Format. Go — функция fmt.Printf (fmt.Sprintf для вывода в строку)
Помимо этого, благодаря наличию утилиты 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, ... );