Строка формата printf - printf format string
Эта статья нужны дополнительные цитаты для проверка.Февраль 2015 г.) (Узнайте, как и когда удалить этот шаблон сообщения) ( |
строка формата printf относится к параметру управления, используемому классом функции в библиотеках ввода / вывода C и многие другие языки программирования. Строка записывается простым язык шаблона: символы обычно копируются буквально в вывод функции, но спецификаторы формата, которые начинаются с %
символ, укажите расположение и метод перевода части данных (например, числа) в символы.
printf - это имя одной из основных функций вывода языка Си, обозначающее "печать formatted ». Строки формата. printf дополняют строки формата scanf, которые обеспечивают форматированный ввод (разбор ). В обоих случаях они обеспечивают простую функциональность и фиксированный формат по сравнению с более сложными и гибкими шаблонизаторами или синтаксическими анализаторами, но их достаточно для многих целей.
Многие языки, отличные от C, копируют синтаксис строки формата printf точно или точно в свои собственные функции ввода-вывода.
Несоответствие между спецификаторами формата и типом данных может вызвать сбои и другие уязвимости. Сама строка формата очень часто строковый литерал, который позволяет статический анализ вызова функции. Однако это также может быть значение переменной, допускающее динамическое форматирование, но также уязвимость системы безопасности, известная как неконтролируемая строка формата эксплуатировать.
История
Ранние языки программирования, такие как Фортран использовали специальные операторы с совершенно отличным от других вычислений синтаксисом для построения описаний форматирования. В этом примере формат указан в строке 601, а команда WRITE обращается к нему по номеру строки:
ЗАПИСЫВАТЬ ВЫХОД ЛЕНТА 6, 601, Я, IB, IC, ПЛОЩАДЬ 601 ФОРМАТ (4ЧАС А= ,I5,5ЧАС B= ,I5,5ЧАС C= ,I5,& 8ЧАС ПЛОЩАДЬ= ,F10.2, 13ЧАС КВАДРАТ ЕДИНИЦЫ)
АЛГОЛ 68 был более функциональным API, но по-прежнему использовал специальный синтаксис ( $
разделители окружают специальный синтаксис форматирования):
printf(($"Цвет "грамм", номер 1 "6d,", номер 2 "4zd,"шестнадцатеричный"16r2d,", плавать "-d.2d,", беззнаковое значение"-3d"."l $, "красный", 123456, 89, BIN 255, 3.14, 250));
Но использование обычных вызовов функций и типов данных упрощает язык и компилятор, а также позволяет записывать реализацию ввода / вывода на одном языке. Эти преимущества перевешивают недостатки (например, полное отсутствие безопасности типов во многих случаях), и в большинстве новых языков ввод-вывод не является частью синтаксиса.
C printf
берет свое начало в BCPL с writef
функция (1966). В сравнении с C
и printf
, * N
является BCPL язык escape-последовательность, представляющая символ новой строки (для которой C использует escape-последовательность п
), а порядок ширины и типа поля спецификации формата меняется на обратный в writef
:[1]
WRITEF ("ПРОБЛЕМА% I2-QUEENS ИМЕЕТ% I5 РЕШЕНИЙ * N"; NUMQUEENS, COUNT)
Вероятно, первым копированием синтаксиса за пределами языка C был Unix printf
команда оболочки, которая впервые появилась в Версия 4, в составе порта на С.[2]
Спецификация заполнителя формата
Форматирование происходит через заполнители в строке формата. Например, если программа хочет распечатать возраст человека, она может представить результат, поставив перед ним префикс «Ваш возраст» и используя знак десятичного описателя со знаком. d
чтобы обозначить, что мы хотим, чтобы целое число для возраста отображалось сразу после этого сообщения, мы можем использовать строку формата:
printf("Ваш возраст% d", возраст);
Синтаксис
Синтаксис для заполнителя формата:
%[параметр][флаги][ширина][.точность][длина]тип
Поле параметра
Это POSIX расширение, а не в C99. Поле параметра может быть опущено или может быть:
Характер Описание п$ п - это номер параметра, отображаемого с использованием этого спецификатора формата, что позволяет выводить предоставленные параметры несколько раз с использованием различных спецификаторов формата или в разном порядке. Если какой-либо отдельный заполнитель указывает параметр, все остальные заполнители ДОЛЖНЫ также указывать параметр.
Например,printf ("% 2 $ d% 2 $ # x;% 1 $ d% 1 $ # x", 16,17)
производит17 0x11; 16 0x10
.
Эта функция в основном используется при локализации, где порядок появления параметров зависит от языка.
В Microsoft Windows, отличной от POSIX, поддержка этой функции помещена в отдельную функцию printf_p.
Поле флагов
В поле Flags может быть ноль или более (в любом порядке):
Характер Описание -
(минус)Выровняйте по левому краю вывод этого заполнителя. (По умолчанию вывод выравнивается по правому краю.) +
(плюс)Добавляет плюс для положительных числовых типов со знаком. положительный = +, отрицательный = -.
(По умолчанию перед положительными числами ничего не добавляется.)
(Космос)Добавляет пробел для положительных числовых типов со знаком. положительный = , отрицательный = -. Этот флаг игнорируется, если + флаг существует.
(По умолчанию перед положительными числами ничего не добавляется.)0
(нуль)Когда указана опция «ширина», добавляются нули для числовых типов. (По умолчанию пробелы добавляются к началу.)
Например,printf ("% 4X"; 3)
производит3
, покаprintf ("% 04X"; 3)
производит0003
.'
(апостроф)К целому числу или показателю десятичной дроби применяется разделитель группировок тысяч. #
(хеш)Альтернативная форма:
За грамм и грамм типы, нули в конце не удаляются.
За ж, F, е, E, грамм, грамм типов, вывод всегда содержит десятичную точку.
За о, Икс, Икс типы, текст 0, 0x, 0X, соответственно, добавляется к ненулевым числам.
Поле ширины
В поле Ширина указывается минимум количество символов для вывода и обычно используется для заполнения полей фиксированной ширины в табличных выводах, где в противном случае поля были бы меньше, хотя это не приводит к усечению слишком больших полей.
Поле ширины может быть опущено, числовое целочисленное значение или динамическое значение при передаче в качестве другого аргумента, если оно указано звездочкой. *.[3] Например, printf ("% * d", 5, 10)
приведет к 10
печатается общей шириной 5 знаков.
Хотя это и не является частью поля ширины, начальный ноль интерпретируется как флаг заполнения нулями, упомянутый выше, а отрицательное значение обрабатывается как положительное значение в сочетании с выравниванием по левому краю - флаг также упоминался выше.
Поле точности
В поле «Точность» обычно указывается максимум ограничение на вывод, в зависимости от конкретного типа форматирования. Для числовых типов с плавающей запятой он определяет количество цифр справа от десятичной запятой, для которых выходные данные должны быть округлены. Для строкового типа он ограничивает количество выводимых символов, после чего строка усекается.
Поле точности может быть опущено, числовое целочисленное значение или динамическое значение при передаче в качестве другого аргумента, если оно обозначено звездочкой. *. Например, printf («%. * s», 3, «abcdef»)
приведет к abc
печатается.
Поле длины
Поле длины может быть опущено или иметь одно из следующих значений:
Характер Описание чч Для целочисленных типов причины printf ожидать int-размерный целочисленный аргумент, который был повышен из char. час Для целочисленных типов причины printf ожидать int-размерный целочисленный аргумент, который был повышен из короткая. л Для целочисленных типов причины printf ожидать длинный-размерный целочисленный аргумент. Для типов с плавающей запятой это игнорируется. плавать аргументы всегда продвигаются к двойной при использовании в вызове varargs. [4]
ll Для целочисленных типов причины printf ожидать долго долго-размерный целочисленный аргумент. L Для типов с плавающей запятой причины printf ожидать длинный двойной аргумент. z Для целочисленных типов причины printf ожидать size_t-размерный целочисленный аргумент. j Для целочисленных типов причины printf ожидать intmax_t-размерный целочисленный аргумент. т Для целочисленных типов причины printf ожидать ptrdiff_t-размерный целочисленный аргумент.
Кроме того, до широкого использования расширений ISO C99 появилось несколько вариантов длины для конкретных платформ:
Символы Описание я Для целочисленных типов со знаком причины printf ожидать ptrdiff_t-размерный целочисленный аргумент; для беззнаковых целочисленных типов причины printf ожидать size_t-размерный целочисленный аргумент. Обычно встречается на платформах Win32 / Win64. I32 Для целочисленных типов причины printf ожидать 32-битный (двойное слово) целочисленный аргумент. Обычно встречается на платформах Win32 / Win64. I64 Для целочисленных типов причины printf ожидать 64-битный (четверное слово) целочисленный аргумент. Обычно встречается на платформах Win32 / Win64. q Для целочисленных типов причины printf ожидать 64-битный (четверное слово) целочисленный аргумент. Обычно встречается на платформах BSD.
ISO C99 включает inttypes.h
заголовочный файл, который включает ряд макросов для использования в платформенно-независимых printf
кодирование. Они должны быть вне двойных кавычек, например printf ("%" PRId64 " n", t);
Примеры макросов включают:
Макрос Описание PRId32 Обычно эквивалентно I32d (Win32 / Win64) или же d PRId64 Обычно эквивалентно I64d (Win32 / Win64), lld (32-битные платформы) или же ld (64-битные платформы) PRIi32 Обычно эквивалентно I32i (Win32 / Win64) или же я PRIi64 Обычно эквивалентно I64i (Win32 / Win64), lli (32-битные платформы) или же Ли (64-битные платформы) PRIu32 Обычно эквивалентно I32u (Win32 / Win64) или же ты PRIu64 Обычно эквивалентно I64u (Win32 / Win64), llu (32-битные платформы) или же Лу (64-битные платформы) PRIx32 Обычно эквивалентно I32x (Win32 / Win64) или же Икс PRIx64 Обычно эквивалентно I64x (Win32 / Win64), llx (32-битные платформы) или же лк (64-битные платформы)
Поле типа
Поле Тип может быть любым из:
Характер Описание % Печатает буквальный % символ (этот тип не принимает поля флагов, ширины, точности, длины). d, я int как подписанный целое число. % d и %я являются синонимами вывода, но отличаются при использовании с сканф
для ввода (где используется %я интерпретирует число как шестнадцатеричное, если ему предшествует 0x, и восьмеричное, если ему предшествует 0.)ты Печать десятичной дроби беззнаковое целое. ж, F двойной в нормальном (фиксированная точка ) обозначение. ж и F отличается только тем, как печатаются строки для бесконечного числа или NaN (инф, бесконечность и нан за ж; INF, БЕСКОНЕЧНОСТЬ и NAN за F). е, E двойной значение в стандартной форме (d.ддде ±дд). An E преобразование использует букву E (скорее, чем е) ввести показатель степени. Показатель степени всегда состоит как минимум из двух цифр; если значение равно нулю, показатель степени равен 00. В Windows показатель степени по умолчанию состоит из трех цифр, например 1.5e002, но это может быть изменено специфичным для Microsoft _set_output_format
функция.грамм, грамм двойной в нормальном или экспоненциальном представлении, в зависимости от того, что больше подходит для его величины. грамм использует строчные буквы, грамм использует заглавные буквы. Этот тип немного отличается от записи с фиксированной точкой тем, что незначащие нули справа от десятичной точки не включаются. Кроме того, десятичная точка не включается в целые числа. Икс, Икс беззнаковое целое как шестнадцатеричный номер. Икс использует строчные буквы и Икс использует верхний регистр. о беззнаковое целое в восьмеричном. s строка с завершающим нулем. c char (персонаж). п пустота* (указатель на void) в формате, определяемом реализацией. а, А двойной в шестнадцатеричной системе счисления, начиная с 0x или же 0X. а использует строчные буквы, А использует заглавные буквы.[5][6] (Iostreams C ++ 11 имеют hexfloat это работает так же). п Ничего не печатает, но записывает количество успешно записанных на данный момент символов в параметр целочисленного указателя.
Java: указывает на нейтральную платформу новую строку / возврат каретки.[7]
Примечание: это можно использовать в Строка неконтролируемого формата подвиги.
Заполнители нестандартного формата
Есть несколько реализаций printf
-подобные функции, которые позволяют расширять escape-символ -основан мини-язык, таким образом позволяя программисту иметь специальную функцию форматирования для не встроенных типов. Один из самых известных - (теперь не рекомендуется) glibc с register_printf_function ()
. Однако он редко используется из-за того, что конфликтует с проверкой строки статического формата. Другой Пользовательские форматеры VSTR, что позволяет добавлять имена в многосимвольном формате.
Некоторые приложения (например, HTTP-сервер Apache ) включать свои собственные printf
-подобная функция, и встраивать в нее расширения. Однако все они, как правило, имеют те же проблемы, что и register_printf_function ()
имеет.
В Ядро Linux printk
функция поддерживает несколько способов отображения структур ядра с помощью универсального %п
спецификация, по добавление дополнительные символы формата.[8] Например, % pI4
печатает IPv4 адрес в десятичной форме с точками. Это позволяет проверять строку статического формата ( %п
часть) за счет полной совместимости с обычным printf.
Большинство языков, отличных от C, которые имеют printf
-подобная функция позволяет обойти недостаток этой функции, просто используя % s
формат и преобразование объекта в строковое представление. C ++ предлагает заметное исключение в том, что он имеет printf
функция, унаследованная от своей истории C, но также имеет совершенно другую ввод, вывод механизм, который является предпочтительным.[9]
Уязвимости
Недействительные спецификации преобразования
Если синтаксис спецификации преобразования недопустимы, поведение не определено и может привести к завершению программы. Если их слишком мало аргументы функции предоставляется для предоставления значений для всех спецификаций преобразования в строке шаблона, или, если аргументы не правильного типа, результаты также не определены. Лишние аргументы игнорируются. В ряде случаев неопределенное поведение приводило к "Атака на форматную строку " безопасность уязвимости.
Некоторые компиляторы, например Коллекция компиляторов GNU, будет статически проверять строки формата printf-подобных функций и предупреждать о проблемах (при использовании флагов -Стена
или же -Wformat
). GCC также будет предупреждать об определяемых пользователем функциях в стиле printf, если нестандартный "формат" __атрибут__
применяется к функции.
Ширина поля по сравнению с явными разделителями в табличном выводе
Использование только ширины полей для табуляции, как в таком формате, как % 8д% 8д% 8д
для трех целых чисел в трех 8-символьных столбцах не гарантирует, что разделение полей будет сохранено, если в данных встречаются большие числа. Отсутствие разделения полей может легко привести к повреждению вывода. В системах, которые поощряют использование программ в качестве строительных блоков в сценариях, такие поврежденные данные часто могут быть перенаправлены и повредят дальнейшую обработку, независимо от того, ожидал ли исходный программист, что результат будет прочитан только человеческими глазами. Такие проблемы можно устранить, включив явные разделители, даже пробелы, во все табличные форматы вывода. Просто изменив опасный пример с предыдущего на % 7д% 7д% 7д
решает эту проблему, идентифицируя форматирование до тех пор, пока числа не станут больше, но затем явно предотвращает их объединение при выводе из-за явно включенных пробелов. Аналогичные стратегии применимы к строковым данным.
Языки программирования с printf
Языки, в которых используются строки формата, отличные от стиля, описанного в этой статье (например, AMPL и Эликсир ), языки, которые наследуют свою реализацию от JVM или в другой среде (например, Clojure и Scala ), и языки, которые не имеют стандартной собственной реализации printf, но имеют внешние библиотеки, которые имитируют поведение printf (например, JavaScript ) не включены в этот список.
- awk (через sprintf)
- C
- C ++ (также предоставляет перегружен операторы и манипуляторы сдвига в качестве альтернативы форматированного вывода - см. iostream и иоманип )
- Цель-C
- D
- F #
- ГРАММ (LabVIEW )
- GNU MathProg
- GNU Octave
- Идти
- Haskell
- J
- Ява (с версии 1.5) и языки JVM
- Lua (строка.формат)
- Клен
- MATLAB
- Максимум (через объект sprintf)
- Мифрил
- PARI / GP
- Perl
- PHP
- Python (через оператор%)
- р
- Раку (через
printf
,спринт
, иfmt
) - Красный / Система
- Рубин
- Tcl (через команду форматирования)
- Transact-SQL (через xp_sprintf )
- Вала (через
Распечатать()
иFileStream.printf ()
) - В
printf
служебная команда, иногда встроенная в оболочку, как некоторые реализации KornShell (кш), Борн снова оболочка (bash), или Z оболочка (zsh). Эти команды обычно интерпретируют C убегает в строке формата.
Смотрите также
- Формат (Common Lisp)
- Стандартная библиотека C
- Атака на форматную строку
iostream
- ML (язык программирования)
- printf отладка
printf
(Unix)printk
(распечатать сообщения ядра)сканф
- строковая интерполяция
Рекомендации
- ^ «BCPL». www.cl.cam.ac.uk. Получено 19 марта 2018.
- ^ Макилрой, М.Д. (1987). Читатель Research Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (Технический отчет). CSTR. Bell Labs. 139.
- ^ "printf - Справочник по C ++". www.cplusplus.com. Получено 10 июн 2020.
- ^ ISO /IEC (1999). ISO / IEC 9899: 1999 (E): Языки программирования - C §7.19.6.1 пункт 7
- ^ ""Справочное руководство библиотеки GNU C "," 12.12.3 Таблица преобразований вывода"". Gnu.org. Получено 17 марта 2014.
- ^ "printf" (% a добавлено в C99)
- ^ «Форматирование вывода числовой печати». Учебники по Java. Oracle Inc. Получено 19 марта 2018.
- ^ "Документация по ядру Linux / printk-sizes.txt". Git.kernel.org. Получено 17 марта 2014.
- ^ Бьярн Страуструп (1997). Язык программирования C ++ (третье изд.). Эддисон-Уэсли. стр.637–640. ISBN 0-201-88954-4.
внешняя ссылка
- Справочник по C ++ для
std :: fprintf
- Краткий справочник спецификаций формата gcc printf
- Единая спецификация UNIX, Выпуск 7 из Открытая группа : форматированный вывод для печати - Справочник по системным интерфейсам,
- В
Форматировщик
Технические характеристики в Java 1.5 - GNU Bash
printf (1)
встроенный