Jump to content

печать

Пример функции printf

printf — это C стандартной библиотеки функция , которая форматирует текст и записывает его в стандартный вывод .

Имя printf является сокращением от print format , где print относится к выводу на принтер, хотя функции не ограничиваются выводом на принтер.

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

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

строки формата Синтаксис и семантика одинаковы для всех функций семейства printf.

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

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

Дизайн форматирования был скопирован в другие языки программирования .

1950-е: Фортран

[ редактировать ]

Ранние языки программирования, такие как Фортран, использовали специальные операторы с синтаксисом, отличным от синтаксиса других вычислений, для создания описаний форматирования. [1] В этом примере формат указан в строке 601, а команда PRINT [а] команда ссылается на него по номеру строки:

      PRINT 601, IA, IB, AREA
 601  FORMAT (4H A= ,I5,5H  B= ,I5,8H  AREA= ,F10.2, 13H SQUARE UNITS)

Настоящим:

  • 4H указывает строку из 4 символов " A= " ( H означает Холлерит Филд );
  • I5 указывает целочисленное поле шириной 5;
  • F10.2 указывает поле с плавающей запятой шириной 10 и двумя цифрами после десятичной точки.

Вывод с входными аргументами 100, 200 и 1500,25 может выглядеть следующим образом:

 A=   100  B=   200  AREA=    1500.25 SQUARE UNITS

1960-е: BCPL и АЛГОЛ 68.

[ редактировать ]

В 1967 году BCPL . появился [2] Его библиотека включала в себя writef рутина. [3] Пример приложения выглядит так:

WRITEF("%I2-QUEENS PROBLEM HAS %I5 SOLUTIONS*N", NUMQUEENS, COUNT)

Настоящим:

  • %I2 указывает целое число ширины 2 (порядок ширины и типа поля спецификации формата обратный по сравнению с C printf);
  • %I5 указывает целое число шириной 5;
  • *N BCPL, — это escape-последовательность языка представляющая символ новой строки (для которого C использует escape-последовательность \n).

В 1968 году АЛГОЛ 68 имел более функциональный API , но по-прежнему использовал специальный синтаксис ( $ разделители окружают специальный синтаксис форматирования):

printf(($"Color "g", number1 "6d,", number2 "4zd,", hex "16r2d,", float "-d.2d,", unsigned value"-3d"."l$,
         "red", 123456, 89, BIN 255, 3.14, 250));

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

В 1973 году printf включен как подпрограмма C как часть версии 4 Unix . [4]

1990-е: Командование Shell

[ редактировать ]

В 1990 году printf Команда оболочки сертифицирована как часть 4.3BSD-Reno . Он создан по образцу стандартной библиотечной функции. [5]

В 1991 году printf Команда входит в состав GNU Shellutils (теперь часть GNU Core Utilities ).

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

[ редактировать ]

Форматирование значения указывается как разметка в строке формата. Например, следующие выходные данные: «Ваш возраст», а затем значение переменной age в десятичном формате.

printf("Your age is %d", age);

Синтаксис

[ редактировать ]

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

%[parameter][flags][width][.precision][length]type

Поле параметра

[ редактировать ]

Поле параметра является необязательным. Если включено, то сопоставление спецификаторов со значениями не является последовательным. Числовое значение n выбирает n-й параметр значения.

Характер Описание
п $ n — индекс параметра значения для сериализации с использованием этого спецификатора формата.

Это расширение POSIX ; не С99 .

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

Например,

printf("%2$d %2$#x; %1$d %1$#x",16,17)

выходы: 17 0x11; 16 0x10.

Это поле особенно полезно для локализации сообщений на разные естественные языки , в которых часто используется разный порядок слов.

В Microsoft Windows поддержка этой функции осуществляется с помощью другой функции: printf_p.

Поле флагов

[ редактировать ]

Поле flags может содержать ноль или более следующих значений (в любом порядке):

Характер Описание
-
(минус)
Выровняйте выходные данные этого заполнителя по левому краю. (По умолчанию вывод выравнивается по правому краю.)
+
(плюс)
Добавляет плюс для положительных числовых типов со знаком. положительный = +, отрицательный = -.
(По умолчанию ничего не добавляется перед положительными числами.)

(космос)
Добавляет пробел для положительных числовых типов со знаком. положительный = , отрицательный = -. Этот флаг игнорируется, если + флаг существует.
(По умолчанию ничего не добавляется перед положительными числами.)
0
(ноль)
Если указана опция «ширина», для числовых типов добавляются нули. (По умолчанию добавляются пробелы.)
Например, printf("%4X",3) производит 3, пока printf("%04X",3) производит 0003.
'
(апостроф)
К целому числу или показателю десятичной дроби применяется разделитель групп тысяч.
#
(хэш)
Альтернативная форма:
Для г и Типы G , конечные нули не удаляются.
Для ж , Ф , и , И , г , Типы G выходные данные всегда содержат десятичную точку.
Для о , х , X типы, текст 0 , 0x , 0X соответственно добавляется к ненулевым числам.

Поле ширины

[ редактировать ]

Поле ширины определяет минимальное количество выводимых символов. Если значение может быть представлено меньшим количеством символов, то оно дополняется слева пробелами, чтобы на выходе было указанное количество символов. Если для значения требуется больше символов, длина вывода превышает указанную ширину. Значение никогда не усекается.

Например, printf("%3d", 12) задает ширину 3 и выводит 12 с пробелом слева для вывода 3 символов. Звонок printf("%3d", 1234) результаты 1234 длина которого составляет 4 символа, поскольку это минимальная ширина для этого значения, хотя указанная ширина равна 3.

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

Если поле указано как *, то значение ширины считывается из списка значений в вызове. [6] Например, printf("%*d", 3, 10) результаты 10 где второй параметр, 3, — это ширина (соответствует *), а 10 — значение для сериализации (совпадает с d).

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

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

  1   1
 12  12
123 123
1234 123

Прецизионное поле

[ редактировать ]

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

Поле точности может быть опущено или может быть целочисленным значением или динамическим значением, если оно передается в качестве другого аргумента, если оно отмечено звездочкой. *. Например, printf("%.*s", 3, "abcdef") результаты абв .

Поле длины

[ редактировать ]

Поле длины может быть опущено или иметь любое из следующих значений:

Характер Описание
хх Для целочисленных типов причины printf ожидать Целочисленный аргумент размера int , который был повышен из чар .
час Для целочисленных типов причины printf ожидать Целочисленный аргумент размера int , который был повышен из короткий .
л Для целочисленных типов причины printf ожидать длинный целочисленный аргумент.

Для типов с плавающей запятой это игнорируется. Аргументы с плавающей запятой всегда повышаются до double при использовании в вызове с переменными аргументами. [7]

я буду Для целочисленных типов причины printf ожидать длинный целочисленный аргумент длинного размера.
л Для типов с плавающей запятой причины printf ожидать длинный двойной аргумент.
С Для целочисленных типов причины printf ожидать size_t — целочисленный аргумент размера.
дж Для целочисленных типов причины 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
д Для целочисленных типов причины printf ожидает 64-битный целочисленный аргумент (четыре слова). БСД

ISO C99 включает в себя inttypes.h заголовочный файл, который включает в себя ряд макросов для независимого от платформы printf кодирование. Например: printf("%" PRId64, t); определяет десятичный формат для 64-битного целого числа со знаком. Поскольку макросы вычисляют строковый литерал, а компилятор объединяет соседние строковые литералы, выражение "%" PRId64 компилируется в одну строку.

Макросы включают в себя:

Макрос Описание
ПРИД32 Обычно эквивалентно I32d ( Win32/Win64 ) или д
ПРИД64 Обычно эквивалентно I64d ( Win32/Win64 ), lld ( 32-битные платформы ) или ld ( 64-битные платформы )
ПРИи32 Обычно эквивалентно I32i ( Win32/Win64 ) или я
PRIi64 Обычно эквивалентно I64i ( Win32/Win64 ), lli ( 32-битные платформы ) или li ( 64-битные платформы )
ПРИУ32 Обычно эквивалентно I32u ( Win32/Win64 ) или в
ПРИУ64 Обычно эквивалентно И64у ( Win32/Win64 ), llu ( 32-битные платформы ) или lu ( 64-битные платформы )
ПРИКС32 Обычно эквивалентно I32x ( Win32/Win64 ) или х
ПРИКС64 Обычно эквивалентно I64x ( Win32/Win64 ), llx ( 32-битные платформы ) или lx ( 64-битные платформы )

Тип поля

[ редактировать ]

Поле типа может быть любым из:

Характер Описание
% Печатает литерал Символ % (этот тип не принимает никаких полей флагов, ширины, точности и длины).
д , я int как целое число со знаком . %d и %i являются синонимами вывода, но различаются при использовании с scanf для ввода (где используется %i будет интерпретировать число как шестнадцатеричное, если ему предшествует 0x и восьмеричный, если ему предшествует 0 .)
в Печать десятичной дроби беззнаковый int .
ж , Ф double в нормальной записи ( с фиксированной запятой ). е и F отличается только тем, как печатаются строки для бесконечного числа или NaN ( инфа , бесконечность и действующий ж ; ИНФ , БЕСКОНЕЧНОСТЬ и НАН сильный Ф ).
и , И двойное значение в стандартной форме ( д . ддд е± дд ). Ан В преобразовании E используется буква Е (а не д ) ввести показатель степени. Показатель степени всегда содержит не менее двух цифр; если значение равно нулю, показатель степени равен 00 . В Windows показатель степени по умолчанию содержит три цифры, например 1.5e002 , но это может быть изменено специфичными для Microsoft _set_output_format функция.
г , Г удваивается либо в нормальной, либо в экспоненциальной записи, в зависимости от того, что больше соответствует его величине. g использует строчные буквы, G использует заглавные буквы. Этот тип немного отличается от записи с фиксированной запятой тем, что незначащие нули справа от десятичной точки не включаются. Кроме того, десятичная точка не включается в целые числа.
х , Х unsigned int как шестнадцатеричное число. x использует строчные буквы и X использует верхний регистр.
тот беззнаковое целое число в восьмеричном формате.
с строка с нулевым завершением .
с чар (персонаж).
п void* (указатель на void) в формате, определяемом реализацией.
а , А двойной в шестнадцатеричной записи, начиная с 0x или 0X . a использует строчные буквы, A использует заглавные буквы. [8] [9] (С++ 11 iostreams имеют hexfloat , который работает так же).
н Ничего не выводит, но записывает количество записанных символов в параметр целочисленного указателя.
В Java это печатает новую строку. [10]

Пользовательское форматирование типов данных

[ редактировать ]

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

Некоторые функции, подобные printf, позволяют расширять escape-символов на основе мини-язык , что позволяет программисту использовать определенную функцию форматирования для невстроенных типов. Одним из них является (сейчас устаревший) glibc . register_printf_function(). Однако он используется редко из-за того, что конфликтует с проверкой статической строки формата. Другой вариант — пользовательские форматтеры Vstr , которые позволяют добавлять имена многосимвольных форматов.

Некоторые приложения (например, HTTP-сервер Apache ) включают в себя собственную функцию, подобную printf, и встраивают в нее расширения. Однако все они, как правило, имеют те же проблемы, что и register_printf_function() имеет.

Ядро Linux printk функция поддерживает несколько способов отображения структур ядра с использованием универсального %p спецификации путем добавления дополнительных символов формата. [11] Например, %pI4 печатает адрес IPv4 в десятичном формате с точками. Это позволяет проверять статическую строку формата (из %p часть) за счет полной совместимости с обычным printf.

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

fprintf выводит в объект системного файла, который позволяет выводить данные в формат, отличный от стандартного вывода.

sprintf записывает в строковый буфер вместо стандартного вывода.

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

Для большинства функций семейства printf существует вариант, который принимает va_list а не список параметров переменной длины. Например, есть vfprintf, vsprintf, vsnprintf.

Уязвимости

[ редактировать ]

Атака по форматной строке

[ редактировать ]

Дополнительные параметры значения игнорируются, но если строка формата содержит больше спецификаторов формата, чем переданные параметры значения, поведение не определено . Для некоторых компиляторов C дополнительный спецификатор формата приводит к использованию значения, даже если его нет. Это может позволить провести атаку на форматную строку . Обычно в языке C аргументы передаются в стеке. Если передано слишком мало аргументов, printf сможет прочитать данные за пределами кадра стека, что позволит злоумышленнику прочитать стек.

Некоторые компиляторы, такие как GNU Compiler Collection , статически проверяют строки формата функций, подобных printf, и предупреждают о проблемах (при использовании флагов -Wall или -Wformat). GCC также будет предупреждать о определяемых пользователем функциях в стиле printf, если нестандартный «формат» __attribute__ применяется к функции.

Эксплойт неконтролируемой строки формата

[ редактировать ]

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

Запись в память

[ редактировать ]

Хотя функция вывода на первый взгляд, printf позволяет записывать в ячейку памяти, указанную аргументом через %n. Эта функция иногда используется как часть более сложных атак с использованием форматной строки. [12]

The %n функциональность также делает printf случайно- Тьюринг-полной даже при правильно сформированном наборе аргументов. Игра в крестики-нолики, записанная в формате string, стала победителем 27-го IOCCC . [13]

Языки программирования с помощью printf

[ редактировать ]

Известные языки программирования, включающие printf или функциональность, подобную printf.

Исключены языки, использующие строки формата, отличающиеся от стиля, описанного в этой статье (например, AMPL и Elixir ), языки, которые наследуют свою реализацию от JVM или другой среды (например, Clojure и Scala ), а также языки, не имеющие стандарта. встроенная реализация printf, но есть внешние библиотеки, которые эмулируют поведение printf (например, JavaScript ).

См. также

[ редактировать ]

Примечания

[ редактировать ]
  1. ^ Согласно руководству по Фортрану 1956 года. [1] , PRINT Команда печатается на подключенном принтере . В руководстве также представлена ​​команда WRITE OUTPUT TAPE который также использует FORMAT заявление для записи на магнитофон .
  1. ^ Jump up to: Перейти обратно: а б Бэкус, Джон Уорнер ; Бибер, Р.Дж.; Бест, Шелдон Ф.; Гольдберг, Ричард ; Херрик, Харлан Л.; Хьюз, РА; Митчелл, LB; Нельсон, Роберт А.; Натт, Рой ; Сэйр, Дэвид ; Шеридан, Питер Б.; Стерн, Гарольд; Циллер, Ирвинг (15 октября 1956 г.). Сэйр, Дэвид (ред.). Система автоматического кодирования FORTRAN для IBM 704 EDPM: Справочное руководство программиста (PDF) . Нью-Йорк, США: Отдел прикладных наук и отдел исследований в области программирования, International Business Machines Corporation . стр. 26–30. Архивировано (PDF) из оригинала 4 июля 2022 года . Проверено 4 июля 2022 г. (2+51+1 стр.)
  2. ^ «БЦПЛ» . cl.cam.ac.uk. ​Проверено 19 марта 2018 г.
  3. ^ Ричардс, Мартин; Уитби-Стривенс, Колин (1979). BCPL — язык и его компилятор . Издательство Кембриджского университета. п. 50 .
  4. ^ Макилрой, доктор медицины (1987). Читатель Research Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (Технический отчет). CSTR. Лаборатории Белла. 139.
  5. ^ "printf (4.3+Reno BSD)" . man.freebsd.org . Проверено 1 апреля 2024 г.
  6. ^ «принтф» . cplusplus.com . Проверено 10 июня 2020 г.
  7. ^ ИСО / МЭК (1999). ISO/IEC 9899:1999(E): Языки программирования – C §7.19.6.1, параграф 7 .
  8. ^ " "Справочное руководство библиотеки GNU C", "12.12.3 Таблица выходных преобразований" " . Gnu.org . Проверено 17 марта 2014 г.
  9. ^ "принтф" ( %a добавлен в C99)
  10. ^ «Форматирование числового вывода на печать» . Учебники по Java . Оракл Инк . Проверено 19 марта 2018 г.
  11. ^ «Документация ядра Linux/printk-formats.txt» . Git.kernel.org. Архивировано из оригинала 29 апреля 2015 года . Проверено 17 марта 2014 г.
  12. ^ https://www.exploit-db.com/docs/english/28476-linux-format-string-exploitation.pdf [ только URL-адрес PDF ]
  13. ^ «Лучшее из шоу — злоупотребление libc» . Ioccc.org . Проверено 5 мая 2022 г.
  14. ^ " "Базовые спецификации открытой группы, выпуск 7, издание 2018 г.", "POSIX awk", "Операторы вывода" " . pubs.opengroup.org . Проверено 29 мая 2022 г.
  15. ^ «Стандартная библиотека Printf» . Руководство по языку Julia . Проверено 22 февраля 2021 г.
  16. ^ «Встроенные типы: printfФорматирование строк в стиле стиля» , Стандартная библиотека Python , Python Software Foundation , получено 24 февраля 2021 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: ce0f66014ccf46aa5926952beefcc40b__1715030520
URL1:https://arc.ask3.ru/arc/aa/ce/0b/ce0f66014ccf46aa5926952beefcc40b.html
Заголовок, (Title) документа по адресу, URL1:
printf - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)