Что такое код vprintf

Содержание

Функция vprintf, vfprintf, vsprintf, vsnprintf

Действия функций vprintf() , vfprintf() , vsprintf() и vsnprintf() эквивалентны действиям функций printf() , fprintf() , sprintf() и snprintf() соответственно, но список аргументов заменяется указателем на список аргументов. Этот указатель должен иметь тип va_list , который определен в заголовке .

В версии C99 к параметрам buf и format применен квалификатор restrict . Функция vsnprintf() добавлена в версии C99.

Пример

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

Что такое код vprintf

Записывает форматированный вывод данных используя указатель на список параметров.

Синтаксис

Параметры

Место хранения данных для вывода.

Максимальное число сохраняемых символов.

Список указателя на параметры.

Возвращаемое значение

Функции vsprintf and vswprintf возвращают число записанных символов, включая символ завершающего нуля, или отрицательное значение, если происходит ошибка при выводе.

Замечания

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

Обеспечение безопасности! Обратите внимание! на то, что нет никакого способа ограничить число записанных символов, что означает, что код, используя эти функции восприимчив к переполнению буфера. Используйте _vsnprintf вместо него, или вызовите _vscprintf, чтобы определить, какой величины нужен буфер. Кроме того, убедитесь в том, что формат — не определяемая пользователем строка. Для получения дополнительной информации, см. статью Предотвращение переполнения буфера.

Унифицированно-текстовые стандартные отображения

Что такое код vprintf

Функции vprintf , vfprintf , vsprintf , vsnprintf эквивалентны соответствующим функциям printf , fprintf , sprintf , snprintf , исключая то, что они вызываются с va_list, а не с переменным количеством аргументов. Эти функции не вызывают макрос va_end , и поэтому значение ap после вызова неопределенно. Приложение может позже само вызвать va_end(ap) .

Эти восемь функций выводят данные в соответствии со строкой format , которая определяет, каким образом последующие параметры (или доступные параметры переменной длины из stdarg (3)) преобразуют поток вывода.

Возвращаемое значение


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

В некоторых цифровых преобразованиях используется символ десятичной точки или символ тысячной группировки `,’. Текущий символ зависит от переменной LC_NUMERIC. Стандарт POSIX по умолчанию использует символ `.’ и не поддерживает символ группировки. Таким образом, выводит `1234567.89′ в стандарте POSIX, `1234567,89′ в локализации nl_NL и `1.234.567,89′ в локализации da_DK.

Флаги

Пять флагов, описанных выше, определены в стандарте C. В стандарте SUSv2 определен один дополнительный флаг. ‘ При десятичных преобразованиях ( i , d , u , f , g , G ) данные группируются символом тысячной группировки, если информация локализации не указывает на это. Обратите внимание, что многие версии gcc не могут распознать эту опцию и выводят соответствующее предупреждение. SUSv2 не включает %’F.

glibc 2.2 добавит в будущем этот флаг. I При преобразовании целых десятичных чисел ( i , d , u ) вывод использует локальное представление цифр (например арабские цифры). Однако он не включает все локальные определения как определено в outdigits . См. http://sources.redhat.com/ml/libc-alpha/2000-08/msg00230.html

Ширина поля


Точность


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

SUSv2 располагает информацией только о модификаторах длины h (с hd , hi , ho , hx , hX , hn ); l (с ld , li , lo , lx , lX , ln , lc , ls ) и L (с Le , LE , Lf , Lg , LG ).

Тип преобразования


ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ

Печатает дату и вpемя в фоpме `Sunday, July 3, 10:02′, где weekday и month являются указателями на стpоку:

Многие стpаны используют поpядок отобpажения даты в виде «день, месяц, год». Следовательно, междунаpодная веpсия должна отображать значений в pазличных стандаpтах: где format зависит от локальных установок и может менять аpгументы. Оперируя значениями , можно получить `Воскресенье, 3. Июль, 10:02′.

Указание достаточно большой строки и ее вывод (код корректен для обеих версий: glibc 2.0 и glibc 2.1):

СООТВЕТСТВИЕ СТАНДАРТАМ

Что касается возвpащаемого значения snprintf , то стандаpты SUSv2 и C99 пpотивоpечат дpуг дpугу: когда snprintf вызывается с size =0 , тогда SUSv2 пpедусматpивает неопpеделенную величину возвpата, меньшую единицы, а C99 устанавливает в этом случае str pавной NULL и возвpащает значение (как обычно) в виде числа символов, размер которых в выходной стpоке был бы достаточным.

Библиотека Linux libc4 располагает информацией о пяти стандартных флагах C. Она также знает о модификаторах длины g, l, L и преобразованиях cdeEfFgGinopsuxX, где F является синонимом f. Дополнительно она принимает D, O, U как синонимы ld, lo, lu. (Это плохо и привело позже к серьезной ошибке, когда исчезла поддержка %D.) Зависимые от локали символы системы исчисления, разделители тысяч, бесконечность, %m$ и *m$ не поддерживаются.

Библиотека Linux libc5 располагает информацией о пяти стандартных флагах C и флагах локализации, %m$ и *m$, о модификторах длины h,l,L,Z,q, но соотносит типы L и q с long double и сверхдлинным целым (это ошибка). Данная библиотека больше не распознает FDOU, но содержит новый символ преобразования m , который выводит strerror(errno) .

glibc 2.0 сейчас поддерживает символы C и S.

К glibc 2.1 добавлены модификаторы длины hh,j,t,z и символы преобразования a,A. В glibs 2.2 добавлены символы преобразования F с семантикой C99 и флаг I.

ПРИМЕЧАНИЯ ПО ИСТОРИИ


НАЙДЕННЫЕ ОШИБКИ

Библиотека Linux libc4.[45] не имеет функции snprintf , однако предоставляет libbsd, содержащую snprintf , эквивалентную sprintf , то есть игнорирующую аргумент size . Таким образом, использование snprintf с ранними версиями libc4 ведет к серьезным проблемам с безопасностью.

Код типа printf( foo ); часто приводит к ошибке, если foo может содержать символ %. Если в foo записан непроверенный ввод пользователя, то содержит foo может содержать %n, и это вызовет запись в память и создание бреши в безопасности.

Некоторые преобразования чисел с плавающей запятой в ранних версиях libc4 приводили к утечкам памяти.

Что такое код vprintf

Самая актуальная документация по Visual Studio 2020: Документация по Visual Studio 2020.

Печатает Форматированные выходные данные в стандартный выходной поток. Доступны более безопасные версии этих функций; в разделе printf_s _printf_s_l, wprintf_s, _wprintf_s_l.

Параметры

format
Форматирование элемента управления.

argument
Необязательные аргументы.

locale
Используемый языковой стандарт.

Возвращает число выведенных символов или отрицательное значение, если произошла ошибка. Если format — NULL , вызывается обработчик недопустимого параметра, как описано в разделе проверки параметров. Если выполнение может быть продолжено, функция возвращает -1 и устанавливает errno в значение EINVAL . Если EOF (0xFFFF) обнаружена в argument , функция возвращает значение -1.

Сведения о errno и коды ошибок в разделе _doserrno, errno, _sys_errlist и _sys_nerr.

printf Функция форматирует и выводит последовательность символов и значений в стандартный выходной поток stdout . Если следовать аргументы format строку, format строка должна содержать спецификации, которые определяют формат вывода для аргументов. printf и fprintf ведут себя одинаково, за исключением того, что printf записывает вывод в stdout , а не для назначения типа FILE .

wprintf — это двухбайтовая версия printf ; format представляет собой строку расширенных символов. wprintf и printf ведут себя одинаково, если поток открыт в режиме ANSI. printf не поддерживает выходные данные в поток в кодировке Юникод.

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

Универсальное текстовое сопоставление функций

Подпрограмма TCHAR.H _UNICODE и _MBCS не определены _MBCS определено _UNICODE определено
_tprintf printf printf wprintf

format Аргумент состоит из обычных символов, escape-последовательности и (если следуют аргументы format ) спецификации формата. Обычные символы и escape-последовательности копируются stdout в порядке их следования. Например следующая строка:

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

Убедитесь, что format не является строкой, определяемой пользователем.

Универсальное текстовое сопоставление функций

Важно
Подпрограмма Tchar.h _UNICODE и _MBCS не определены _MBCS определено _UNICODE определено
_tprintf printf printf wprintf
_tprintf_l _printf_l _printf_l _wprintf_l
Подпрограмма Обязательный заголовок
printf , _printf_l
wprintf , _wprintf_l или

Консоль не поддерживается в приложениях Магазин Windows 8.x. Стандартные дескрипторы потока, связанные с консолью, stdin , stdout и stderr , необходимо перенаправить, чтобы функции C времени выполнения могли использовать их в приложениях Магазин Windows 8.x. Дополнительные сведения о совместимости см. в разделе Совместимость.

Функция vprintf, vfprintf, vsprintf, vsnprintf

Действия функций vprintf() , vfprintf() , vsprintf() и vsnprintf() эквивалентны действиям функций printf() , fprintf() , sprintf() и snprintf() соответственно, но список аргументов заменяется указателем на список аргументов. Этот указатель должен иметь тип va_list , который определен в заголовке .

Пример

В версии C99 к параметрам buf и format применен квалификатор restrict . Функция vsnprintf() добавлена в версии C99.Данный фрагмент программы иллюстрирует, как нужно вызывать функцию vprintf() . Вызов функции va_start() приводит к созданию указателя на список аргументов переменной длины, причем этот указатель указывает на начало списка аргументов. Этот указатель должен быть использован при вызове функции vprintf() . Вызов функции va_end() очищает указатель на список аргументов переменной длины.

printf

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

Наиболее ярким представителем этого семейства является функция 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-подобный синтаксис строки форматирования используют многие другие языки программирования

Помимо этого, благодаря наличию утилиты 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, vspnprintf) — запись результата в строку (буфер в памяти), а не поток.
  • n (snprintf, vnsprintf) — наличие параметра, ограничивающего максимальное количество символов для записи результата (используется только вместе с префиксом 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

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

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

  • 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 может быть нулевым указателем), в этом случае запись не производится, функция только возвращает правильное возвращаемое значение

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

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

Структура управляющей последовательности

Управляющая последовательность имеет вид

Обязательными составными частями являются символ начала управляющей последовательности ( % ) и тип

Флаги

Знак Название знака Значение В отсутствие этого знака Примечание
дефис выводимое значение выравнивается по левому краю в пределах минимальной ширины поля по правому
+ плюс всегда указывать знак (плюс или минус) для выводимого десятичного числового значения только для отрицательных чисел
  пробел помещать перед результатом пробел, если первый символ значения не знак Вывод может начинаться с цифры. Символ + имеет больший приоритет, чем пробел. Используется только для десятичных числовых значений.
# октоторп «альтернативная форма» вывода значения См. ниже
ноль дополнять поле до ширины, указанной в поле ширина управляющей последовательности, символом 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 ); выведет текст 00000002.5000

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

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

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

:

Знаковый тип Беззнаковый тип
signed char unsigned 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 — другое имя одного из этих типов; такое допущение приемлемо для настоящего рассмотрения

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

:

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

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

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

).

Спецификатор %d , %i , %o , %u , %x , %X %n Примечание
отсутствует int или unsigned int указатель на int
l long int или unsigned long int указатель на long int
hh Аргумент имеет тип int или unsigned int, но принудительно приводится к типу signed char или unsigned char, соответственно указатель на signed char формально существуют только в языке Си начиная со второго стандарта (1999)
h Аргумент имеет тип int или unsigned int, но принудительно приводится к типу short int или unsigned short int, соответственно указатель на short int
ll long long int или unsigned long long int указатель на long long int
j intmax_t или uintmax_t указатель на intmax_t
z size_t (или эквивалентный по размеру знаковый тип) указатель на эквивалентный по размеру size_t знаковый тип
t ptrdiff_t (или эквивалентный по размеру беззнаковый тип) указатель на ptrdiff_t
L __int64 или unsigned __int64 указатель на __int64 Для Borland Builder 6 (спецификатор ll ожидает 32-бит число)

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

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

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

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

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

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

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

:

  • d, i — десятичное знаковое число, размер по умолчанию, sizeof( int ). По умолчанию записывается с правым выравниванием, знак пишется только для отрицательных чисел. ‘ %d ‘ и ‘ %i ‘ ведут себя одинаково при выводе, но имеют разные значения при вводе с помощью функции scanf() ;
  • o — восьмеричное беззнаковое число, размер по умолчанию sizeof( int );
  • u — десятичное беззнаковое число, размер по умолчанию sizeof( int );
  • x и X — шестнадцатеричное число, x использует маленькие буквы (abcdef), X большие (ABCDEF), размер по умолчанию sizeof( int );
  • f и F — числа с плавающей запятой. По умолчанию выводятся с точностью 6, если число по модулю меньше единицы, перед десятичной точкой пишется 0. Величины ±∞ представляются в форме [-]inf или [-]infinity, Величина Nan представляется как [-]nan или [-]nan(любой текст далее). Использование F выводит указанные величины заглавными буквами (-INF, NAN). Аргумент по умолчанию имеет размер double.
  • e и E — числа с плавающей запятой в экспоненциальной форме записи (вида 1.1e+44); e выводит символ «e» в нижнем регистре, E — в верхнем (3.14E+0);
  • g и G — число с плавающей запятой; форма представления зависит от значения величины (f или e);
  • a и A — число с плавающей запятой в шестнадцатеричном виде;
  • c — вывод символа с кодом, соответствующим переданному аргументу; переданное число приводится к типу unsigned char (или wint t, если был указан модификатор длины l);
  • 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). [15]

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

Второй стандарт языка Си (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

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

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

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

:

Пара знакового и беззнакового типов Имя макроса
intN_t и uintN_t PRITN
int_leastN_t и uint_leastN_t PRITLEASTN
int_fastN_t и uint_fastN_t PRITFASTN
intmax_t и uintmax_t PRITMAX
intptr_t и uintptr_t PRITPTR

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

Можно заметить, что для типов 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

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

:

  • поле размера:
значение поля тип
I32 signed __int32, unsigned __int32
I64 signed __int64, unsigned __int64
I ptrdiff_t, size_t
w эквивалентно l для строк и символов

Maple

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

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

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

Уязвимости

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

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

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

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

:

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

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

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

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

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

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

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

:

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

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

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

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

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

:

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

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

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

Выравнивание значений на стеке

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

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

Потенциальное несоответствие размеров

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

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

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

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

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

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

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

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

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

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

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

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

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

В вышеприведённом коде неявно предполагается, что пользователь не будет печатать 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 бита. [17]

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

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

Проблема усугубляется недостаточной стандартизацией форматных строк в разных компиляторах: Например, Embarcadero C++ Builder XE поддерживает строку «%lld» , а для GNU C Compiler 4.4.1 приходится указывать «%I64d» . Тот же GNU C не требует в функции swprintf максимальную длину строки (приходится писать snwprintf

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

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

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

Утилита printf

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

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

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

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

Ссылки

  1. Краткое описание языка BCPL
  2. Руководство по языку Би
  3. Описание функции sprintf в документации Perl
  4. Описание форматирующего оператора для строковых типов в Питоне
  5. Описание функции printf в составе PHP
  6. Описание функции java.io.PrintStream.printf() в Java 1.5
  7. Описание функции printf в документации Ruby
  8. Описание функции string.format в документации Lua
  9. Описание функции format в документации TCL
  10. Описание шаблона строки для printf в документации GNU Octave
  11. Описание printf в документации к Maple<<подст:АИ>>
  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
  14. Описание модуля Printf в документации OCaml
  15. § 7.11.1.1 ISO/IEC 9899:TC2, LC_NUMERIC определяет, в частности, форму представления разделителя дробной и целой части .
  16. Описание уязвимостей printf, Robert C. Seacord: Secure Coding in C and C++. Addison Wesley, September, 2005. ISBN 0-321-33572-4
  17. Описание проблем переноса приложений с 32 на 64 битную архитектуру

Источники

  • 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].
  • Описание строки форматирования в документации к Microsoft Visual Studio 2005 [16]
  • Описание register_printf_function[17], [18]

См. также

Эта статья входит в число хороших статей русскоязычного раздела Википедии.

См. также в других словарях:

Printf — printf обобщённое название семейства функций или методов стандартных или широкоизвестных коммерческих библиотек, или встроенных операторов некоторых языков программирования, используемых для форматного вывода вывода в различные потоки … Википедия

Printf — Saltar a navegación, búsqueda Un ejemplo de la función printf. Numerosos lenguajes de programación implementan una función printf, para mostrar una cadena con formato. Ésta, originaria del lenguaje de programación C, tiene un prototipo similar al … Wikipedia Español

Printf — est une commande Unix permettant de faire afficher une chaîne de caractères à l écran. C est aussi un nom de fonction du Langage C, du Perl et d autres langages informatiques permettant d afficher une ou plusieurs variables de façon formatée dans … Wikipédia en Français

Printf — The >Wikipedia

printf — Un exemple de la fonction printf. printf (pour l anglais print formatted, soit « imprimer formaté ») est une commande Unix permettant de faire afficher une chaîne de caractères à l écran. C est aussi un nom de fonction du langage C, et… … Wikipédia en Français

printf — Un ejemplo de la función printf. Numerosos lenguajes de programación implementan una función printf (print formated), para mostrar una cadena con formato. Ésta, originaria del lenguaje de programación C, tiene un prototipo similar al siguiente:… … Wikipedia Español

Printf() — … Википедия

printf — PRINT Formatted Standard Prozedur mit VARGS, http://www.desy.de/cgi bin/man cgiprintf … Acronyms

printf — ● /print F/ np. m. ►LANGC Fonction très >Dictionnaire d’informatique francophone

Что такое код vprintf

Записывает форматированный вывод данных используя указатель на список параметров.

Синтаксис

Параметры

Место хранения данных для вывода.

Максимальное число сохраняемых символов.

Список указателя на параметры.

Возвращаемое значение

Функции vsprintf and vswprintf возвращают число записанных символов, включая символ завершающего нуля, или отрицательное значение, если происходит ошибка при выводе.

Замечания

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

Обеспечение безопасности! Обратите внимание! на то, что нет никакого способа ограничить число записанных символов, что означает, что код, используя эти функции восприимчив к переполнению буфера. Используйте _vsnprintf вместо него, или вызовите _vscprintf, чтобы определить, какой величины нужен буфер. Кроме того, убедитесь в том, что формат — не определяемая пользователем строка. Для получения дополнительной информации, см. статью Предотвращение переполнения буфера.

Унифицированно-текстовые стандартные отображения

Что такое код vprintf

(PHP 3, PHP 4, PHP 5)

sprintf — Возвращает отформатированную строку

Описание string sprintf ( string format [, mixed args] )

Возвращает строку, созданную с использованием строки формата format .

Строка формата состоит из директив: обычных символов (за исключением % ), которые копируются в результирующую строку, и описатели преобразований , каждый из которых заменяется на один из параметров. Это относится также к fprintf() , sprintf() и printf() .

Каждый описатель прреобразований состоит из знака процента ( % ), за которым следует один или более дополнительных элементов (в том порядке, в котором они здесь перечислены):

Необязательный описатель заполнения , который определяет, какой символ будет использоваться для дополнения результата до необходимой длины. Это может быть пробел или 0 . По умолчанию используется пробел. Альтернативный символ может быть указан с помощью ‘ . См. примеры ниже.

Необязательный описатель выравнивания , определяющий выранивание влево или вправо. По умолчанию выравнивается вправо, — используется для выравнивания влево.

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

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

Описатель типа , определяющий, как трактовать тип данных аргумента. Допустимые типы:

% — символ процента. Аргумент не используется.
b — аргумент трактуется как целое и выводится в виде двоичного числа.
c — аргумент трактуется как целое и выводится в виде символа с соответствующим кодом ASCII.
d — аргумент трактуется как целое и выводится в виде десятичного числа со знаком.
e — аргумент трактуется как float и выводится в научной нотации (например 1.2e+2).
u — аргумент трактуется как целое и выводится в виде десятичного числа без знака.
f — аргумент трактуется как float и выводится в виде десятичного числа с плавающей точкой.
o — аргумент трактуется как целое и выводится в виде восьмеричного числа.
s — аргумент трактуется как строка.
x — аргумент трактуется как целое и выводится в виде шестнадцатиричного числа (в нижнем регистре букв).
X — аргумент трактуется как целое и выводится в виде шестнадцатиричного числа (в верхнем регистре букв).

Начиная с PHP 4.0.6 в строке формата поддерживается нумерация и изменение порядка параметров. Например:

Пример 1. Изменение порядка параметров

= «There are %d monkeys in the %s» ;
printf ( $format , $num , $location );
?>

Этот код выведет «There are 5 monkeys in the tree». Теперь представьте, что строка формата содержится в отдельном файле, который потом будет переведен на другой язык, и мы переписываем ее в таком виде:

Пример 2. Изменение порядка параметров

= «The %s contains %d monkeys» ;
printf ( $format , $num , $location );
?>

Появляется проблема: порядок описателей преобразования не соответствует порядку аргументов. Мы не хотим менять код, и нам нужно указать, какому аргументу соответствует тот или иной описатель преобразования.

Пример 3. Изменение порядка параметров

= «The %2\$s contains %1\$d monkeys» ;
printf ( $format , $num , $location );
?>

Нумерация аргументов имеет еще одно применение: она позволят вывести один и тот же аргумент несколько раз без передачи функции дополнительных параметров.

Пример 4. Изменение порядка параметров

= «The %2\$s contains %1\$d monkeys.
That’s a nice %2\$s full of %1\$d monkeys.» ;
printf ( $format , $num , $location );
?>

Примеры

Пример 5. sprintf() : заполнение нулями

= sprintf ( «%04d-%02d-%02d» , $year , $month , $day );
?>

Пример 6. sprintf() : форматирование денежных величин

C/C++ vprintf

Доброго времени суток!

Положим, у нас есть примерно такой код

Каким образом можно программно определить из format, сколько параметров было передано? Что-нить стандартное есть или придется руками каждый раз считать в строчке количество ‘%’?

А для чего ты пытаешься такое делать?

vprintf() принимает всего два аргумента. Если ты имел ввиду свой велосипед с другим именем, то наверное нет, считать придется вручную. Кода кстати меньше, чем букв в твоем посте.

Пишу один велосипед.

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

А если ты про количество аргументов в общем виде, то ответ нет.

Заюзай холостой подсчет:

Кода кстати меньше, чем букв в твоем посте.

Это тебе только так кажется, код неправильный. Синтаксис строки формата несколько сложнее.

Следовательно, надо узнать длину строкового представления всех передаваемых параметров, следовательно, для начала их бы пересчитать.

Не обязательно писать сразу в файл. Навряд ли будешь

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

Такие заявления надо сопровождать контр-кейсами, чтобы если не меня макнуть, то хотя бы ОП понимал, в чем проблема.

Только передавать адрес dummy не надо, достаточно передать NULL.

The snprintf() function shall be equivalent to sprintf(), with the addition of the n argument which states the size of the buffer referred to by s. If n is zero, nothing shall be written and s may be a null pointer. Otherwise, output bytes beyond the n-1st shall be discarded instead of being written to the array, and a null byte is written at the end of the bytes actually written into the array.

(Если кто не в курсе, то по стандарту, если явно не указано иное, в общем виде нужно передавать валидный указатель даже при нулевой длине, например memmove(dst, src, 0)).

Ипать я лоханулся! :D
Сливаюсь!

Такие заявления надо сопровождать контр-кейсами, чтобы если не меня макнуть, то хотя бы ОП понимал, в чем проблема.

Посмотрел бы man 3 printf, там ещё кроме самих данных можно задавать дополнительные атрибуты, типа

Как написать vfprintf обертку, которая добавляет префикс к спецификатору формата и передает новый спецификатор формата к vfprintf в C89?

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

Теперь я не знаю, как сделать это, но я захватил свое намерение в следующем коде.

Вы видите в вышеупомянутом коде, который я хочу к префиксу «foo: ошибка» к спецификатору формата и затем передает его, чтобы vprintf . Этот код, конечно, привел бы к ошибке времени компиляции, потому что этот код не действителен. Это только захватывает мое намерение того, чего я пытаюсь достигнуть.

Можно ли помочь мне написать этот код правильно?

Илон Маск рекомендует:  [атрибут
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL