PRINTF(3) Руководство программиста Linux PRINTF(3)

ИМЯ

printf, fprintf, dprintf, sprintf, snprintf, vprintf, vfprintf, vdprintf, vsprintf, vsnprintf - преобразование форматированного вывода

ОБЗОР

#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
#include <stdarg.h>
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vdprintf(int fd, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

snprintf(), vsnprintf():

_XOPEN_SOURCE >= 500 || _ISOC99_SOURCE || || /* версии glibc <= 2.19: */ _BSD_SOURCE

dprintf(), vdprintf():

Начиная с glibc 2.10:
_POSIX_C_SOURCE >= 200809L
До glibc 2.10:
_GNU_SOURCE

ОПИСАНИЕ

Функции семейства printf() выводят данные в соответствии с параметром format, описанным ниже. Функции printf() и vprintf() направляют данные в стандартный поток вывода stdout; функции fprintf() и vfprintf() направляют данные в заданный поток вывода stream; функции sprintf(), snprintf(), vsprintf() и vsnprintf() направляют данные в символьную строку str.

Функция dprintf() подобна fprintf() за исключением того, что выводит данные в файловый дескриптор fd, а не в поток stdio.

Функции snprintf() и vsnprintf() записывают не более size байт (включая конечный байт null ('\0')) в str.

Функции vprintf(), vfprintf(), vdprintf(), vsprintf(), vsnprintf() эквивалентны printf(), fprintf(), dprintf(), sprintf(), snprintf(), соответственно, за исключением того, что они вызываются с va_list, а не переменным числом аргументов. Эти функции не вызывают макрос va_end. Так как они вызывают макрос va_arg, значение ap не определено после вызова. Смотрите stdarg(3).

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

В C99 и POSIX.1-2001 указано, что результат не определён, если вызов sprintf(), snprintf(), vsprintf() или vsnprintf() привёл бы копированию между перекрывающимися объектами (например, если массив строк назначения и один из указанных входных аргументов ссылаются на один буфер). Смотрите ЗАМЕЧАНИЯ.

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

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

Параметры должны точно соответствовать (после преобразования типа) спецификаторам преобразований. По умолчанию параметры используются в порядке поступления, где каждая «*» (смотрите Ширина поля и Точность ниже) и каждый спецификатор преобразования требуют последующего параметра (если указано недостаточно параметров, то это приведёт к ошибке). Возможно явное указание на то, какой параметр будет следующим, с помощью записи «%m$» вместо «%» и «*m$» вместо «*ю, где десятичная цифра m означает позицию нужного параметра в их списке; список начинается с единицы. Таким образом,

printf("%*d", width, num);

и

printf("%2$*1$d", width, num);

означают одно и то же. Вторая форма записи позволяет производить указание на тот же параметр несколько раз. Стандарт C99 не поддерживает использование «$», который пришёл из Single UNIX Specification. Если используется «$», то он должен использоваться для всех преобразований аргументов и во всех аргументах ширины и точности, но он может быть смешан с форматами «%%», которые не поглощают аргументы. Там может не быть пробелов между числами аргументов, обусловленные использованием «$». Например, если аргументы 1 и 3 определены, то аргумент 2 должен также быть определён где-то в строке параметров.

В некоторых цифровых преобразованиях используется символ разделения целой и дробной частей или символ разделения тысяч. Текущий символ зависит от локали, а именно от значения переменной LC_NUMERIC (смотрите setlocale(3)).В локали POSIX по умолчанию используется символ «.» и не отсутствует символ разделения. Таким образом,


    printf("%'.2f", 1234567.89);

выводит «1234567.89» при локали POSIX, «1234567,89» при локали nl_NL и «1.234.567,89» при локали da_DK.

Флаги

За символом % может быть указано ноль или несколько следующих флагов:

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

Пять флагов, описанных выше, определены в стандарте C99. В стандарте Single UNIX Specification определён ещё один дополнительный флаг.

'
При десятичных преобразованиях (i, d, u, f, F, g, G) результат группируется символом разделителя тысяч, если информация локализации указывает на это (смотрите setlocale(3)). Заметим, что многие версии gcc(1) не могут распознать этот флаг и выводят соответствующее предупреждение (SUSv2 не содержи %'F, но в SUSv3 его добавили).

В glibc 2.2 добавлен ещё один флаг.

При преобразовании целых десятичных чисел (i, d, u) в результате используется альтернативное представление цифр согласно локали. Например, начиная с glibc 2.2.3 это даёт арабско-индийские цифры для персидской локали («fa_IR»).

Ширина поля

Необязательная строка из десятичных цифр (с первой цифрой, отличной от нуля) определяет минимальную ширину поля. Если преобразованное значение имеет меньшее количество знаков, чем ширина поля, то оно слева дополняется пробелами (или справа, если указан флаг выравнивания по левому краю). Вместо строки десятичных цифр можно указать «*» или «*m$» (для некоторого десятичного числа m), чтобы определить ширину поля по ширине следующего аргумента или аргумента с номером m (должен быть типа int), соответственно. Отрицательная ширина поля принимается как флаг «-», устанавливающий положительную ширину поля. Несуществующая или небольшая ширина поля не делает его усечённым; если результат преобразования больше ширины поля, то поле расширяется, чтобы вместить в себя преобразованное значение.

Точность

Необязательный параметр точности в виде знака точки («.») сопровождается необязательной строкой десятичных цифр. Вместо строки десятичных цифр можно указать «*» или «*m$» (для некоторого десятичного числа m), чтобы определить значение точности по следующему аргументу или аргументу с номером m (должен быть типа int), соответственно. Если точность указана как «.», то она обрабатывается как нулевая. Отрицательная точность обрабатывается как если не указывалась совсем. Это позволяет ограничивать количество выводимых символов для преобразований d, i, o, u, x и X; показывать определённое количество цифр после десятичной точки для преобразований a, A, e, E, f и F; показывать максимальное количество значащих цифр для преобразований g и G или максимальное количество символов для печати строк при преобразованиях s и S.

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

Устанавливаются для следующих «преобразований целого» d, i, o, u, x или X.

Преобразование целого числа соответствует аргументам signed char или unsigned char, а также тип преобразования n соответствует указателю на аргумент signed char.
Преобразование целого числа соответствует аргументам short int или unsigned short int, а также тип преобразования n соответствует указателю на аргумент short int.
(эль) Преобразование целого числа соответствует аргументам long int или unsigned long int; тип преобразования n соответствует указателю на аргумент long int; тип преобразования c соответствует аргументу wint_t; тип преобразования s соответствует указателю на аргумент wchar_t.
(эль-эль) Преобразование целого числа соответствует аргументам long long int или unsigned long long int, а также тип преобразования n соответствует указателю на аргумент long long int.
Синоним ll. Является нестандартным расширением, унаследовано от BSD; не используйте в новом коде.
Типы преобразования a, A, e, E, f, F, g или G соответствуют аргументу long double (в C99 допускается %LF, но в SUSv2 нет).
Преобразование целого числа соответствует аргументам intmax_t или uintmax_t, а также тип преобразования n соответствует указателю на аргумент intmax_t.
Преобразование целого числа соответствует аргументам size_t или ssize_t, а также тип преобразования n соответствует указателю на аргумент size_t.
Нестандартный синоним z, который появился до z. Не используйте в новом коде.
Преобразование целого числа соответствует аргументам ptrdiff_t или тип преобразования n соответствует указателю на аргумент ptrdiff_t.

В SUSv3 определено всё вышеперечисленное, за исключением указанных как нестандартное расширение. В SUSv2 определены только модификаторы длины hhd, hi, ho, hx, hX, hn) и lld, li, lo, lx, lX, ln, lc, ls) и LLe, LE, Lf, Lg, LG).

Не по стандарту реализации GNU считают ll и L синонимами, поэтому, например, можно написать llg (синоним стандартного Lg) и Ld (синоним стандартного lld). Такое использование не переносимо.

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

Символы, которые определены как типы преобразования. Типы преобразования и их значения:

Параметр int преобразует символы в их знаковое десятичное отображение. Точность (если указана) задаёт минимальное количество цифр в изображении результата; если результат можно показать с помощью меньшего количества цифр, то слева добавляются незначащие нули. По умолчанию значение точности равно единице. При выводе нуля с нулевой точностью выходной поток будет пуст.
Параметр unsigned int преобразуется в беззнаковое восьмеричное число (o), беззнаковое десятичное (u) или беззнаковое шестнадцатеричное (x и X). Буквы abcdef используются в преобразованиях x; буквы ABCDEF используются в преобразованиях X. Точность (если указана) задаёт минимальное количество цифр в изображении результата; если результат можно показать с помощью меньшего количества цифр, то слева добавляются незначащие нули. По умолчанию значение точности равно единице. При выводе нуля с нулевой точностью выходной поток будет пуст.
Параметр double округляется и преобразуется в десятичное выражение в виде [-]d.ddde±dd, где количество цифр после десятичной точки указывает на требуемую точность. Если точность отсутствует, она принимается равной 6-и; если точность равна нулю, десятичная точка не показывается. В преобразовании для представление экспоненты E используется буква E (а не e). В экспоненте всегда не менее двух цифр; если значение ноль, то экспонента выводится как 00.
Параметр double округляется и преобразуется в десятичное выражение в виде [-]ddd.ddd, где количество цифр после десятичной точки указывает на требуемую точность. Если точность отсутствует, она принимается равной 6-и; если точность равна нулю, десятичная точка не показывается. Если десятичная точка есть, перед ней должна быть минимум одна цифра
(в SUSv2 отсутствует информация о F и указано, что этот символ предназначен для отображения символов бесконечности и NaN. В SUSv3 добавлен тип F. В стандарте C99 определены «[-]inf» или «[-]infinity» для указания бесконечности, и строка начинающаяся с «nan» для NaN в случае, если тип преобразования равен f, а начинающаяся с «[-]INF», «[-]INFINITY» или «NAN» в случае, если тип преобразования равен F).
Параметр double преобразуется в стиле f или e (или F или E, для преобразования G). Точность определяется количеством значащих цифр. Если точность отсутствует, то она определяется равной 6-и цифрам; если точность равна нулю, то она трактуется как 1. Стиль e используется, если экспонента преобразования меньше -4, или больше или равна ей. Завершающие нули удаляются из дробной части результата; десятичная точка стоит, только если за ней следует, по крайней мере, одна цифра.
(C99; отсутствует в SUSv2, до добавлено в SUSv3) Для преобразования типа a параметр double отображается в шестнадцатеричной форме (с помощью букв abcdef) вида [-]0xh.hhhhp±; для преобразований типа A используется префикс 0X, буквы ABCDEF и и разделитель экспоненты P. Точность равна шестнадцатеричному разряду перед десятичной точкой и количеству цифр после неё. По умолчанию точность принимается равной точному значению разряда, если оно соответствует ему по основанию 2, и в противном случае размер её является достаточным для определения значения типа double. Разряд перед десятичной точкой не определён для ненормализованных чисел и не равен нулю, но не определён для нормализованных чисел.
Если модификатор l не указан, то параметр int преобразуется в unsigned char и выводится как результирующее значение. Если l указан, то параметр wint_t (широкий символ) преобразуется в многобайтовую последовательность вызовом функции wcrtomb(3); первое его значение преобразуется в начальное значение и выводится в виде многобайтовой строки.
Если модификатор l не указан: параметр const char * преобразуется в указатель на массив символьного типа (строковый указатель). Символы из массива выводятся до конечного байта null ('\0', не включая его); если указана точность, то выводится не более установленного количества символов. Если точность указана, то байт null не нужен. Если точность не указана или она больше, чем размер массива, то массив должен содержать конечный байт null.
Если модификатор l указан: параметр const wchar_t * должен быть указателем на массив широких символов. Широкие символы из массива преобразуются в многобайтовые символы (каждый вызовом функции wcrtomb(3), при этом первое значение преобразуется в начальное значение первого широкого символа) и так до конечного широкого символа null. Результирующие многобайтовые символы выводятся до конечного байта null (не включая его). Если указана точность, то выводится количество байтов, не превышающее это значение, а оставшаяся часть многобайтовых символов не выводится. Заметим, что точность определяется количеством выведенных байт, не широких символов или положением на экране. Массив должен содержать конечный широкий символ null, если точность не указана, и содержать количество байт, меньше размера массива.
(отсутствует в C99 или C11, но есть в SUSv2, SUSv3 и SUSv4) Синоним lc. Не используйте.
(отсутствует в C99 или C11, но есть в SUSv2, SUSv3 и SUSv4) Синоним ls. Не используйте.
Параметр указателя void *, выводящийся в шестнадцатеричном виде (также как при %#x или %#lx).
Количество символов, выводящихся в целом типе int * (или других) без преобразующих параметров. Данный параметр должен быть int * или его вариантом, размер которого совпадает с (необязательно) указываемым целым модификатором длины. Параметр не преобразуется (данный тип не поддерживается библиотекой bionic C). Поведение не определено, если тип преобразования содержит флаги, ширину поля или точность.
(расширение glibc; поддерживается uClibc и musl) Выводит содержимое strerror(errno). Параметр не требуется.
%
Выводит символ '%'. Параметр не требуется. Полный спецификатор преобразования — '%%'.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

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

Функции snprintf() и vsnprintf() записывают не более size байт (включая конечный байт null ('\0')). Если вывод был обрезан из-за данного ограничения, то возвращаемое значение это количество символов (не включая конечный байт null), которое было бы записано в результирующую строку, если бы было достаточно места. Таким образом, если возвращённое значение больше или равно size, то вывод был обрезан (также смотрите ЗАМЕЧАНИЯ ниже).

Если возникла ошибка, то возвращается отрицательное значение.

АТРИБУТЫ

Описание терминов данного раздела смотрите в attributes(7).

Интерфейс Атрибут Значение
printf(), fprintf(), sprintf(), snprintf(), vprintf(), vfprintf(), vsprintf(), vsnprintf() Безвредность в нитях MT-Safe locale

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

fprintf(), printf(), sprintf(), vprintf(), vfprintf(), vsprintf(): POSIX.1-2001, POSIX.1-2008, C89, C99.

snprintf(), vsnprintf(): POSIX.1-2001, POSIX.1-2008, C99.

Функции dprintf() и vdprintf() изначально являлись расширениями GNU, но позже были стандартизованы в POSIX.1-2008.

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

В glibc 2.1 добавлены модификаторы длины hh, j, t и z и символы преобразования a и A.

В glibc 2.2 добавлен символ преобразования F с семантикой C99, а также флаг I.

ЗАМЕЧАНИЯ

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

sprintf(buf, "%s some further text", buf);

для добавления текста в buf. Однако в стандартах явно сказано, что результат не определён, если буферы источника и приёмника перекрываются при вызовах sprintf(), snprintf(), vsprintf() и vsnprintf(). В зависимости о версии gcc(1) и указанных параметрах компилятора, подобные вызовы не приводят к ожидаемым результатам.

Реализация функций snprintf() и vsnprintf() в glibc 2.1 соответствует стандарту C99 как было описано выше. До glibc 2.0.6, они возвращали -1 при обрезанном выводе.

ДЕФЕКТЫ

Так как sprintf() и vsprintf() работают со строкой произвольной длины, вызывающие должны стараться не переполнить реальное пространство; часто это невозможно гарантировать. Заметим, что длина получаемых строк зависит от локали и её сложно предсказать. Вместо них используйте snprintf() и vsnprintf() (или asprintf(3) и vasprintf(3)).

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

ПРИМЕР

Печать Pi с пятью знаками:

#include <math.h>
#include <stdio.h>
fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));

Печать даты и времени в виде «Sunday, July 3, 10:02», где weekday и month указатели на строки:

#include <stdio.h>
fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",

        weekday, month, day, hour, min);

Во многих странах используется порядок день-месяц-год. Вот печать аргументов в формате с учётом интернациональности:

#include <stdio.h>
fprintf(stdout, format,

        weekday, month, day, hour, min);

где format зависит от локали и может переставлять аргументы. Со значением:

"%1$s, %3$d. %2$s, %4$d:%5$.2d\n"

получается «Sonntag, 3. Juli, 10:02».

Выделение достаточно большой строки и печать в неё (код работает и с glibc 2.0, и с glibc 2.1):

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *
make_message(const char *fmt, ...)
{

    int size = 0;

    char *p = NULL;

    va_list ap;

    /* определим требуемый размер */

    va_start(ap, fmt);

    size = vsnprintf(p, size, fmt, ap);

    va_end(ap);

    if (size < 0)

        return NULL;

    size++;             /* для '\0' */

    p = malloc(size);

    if (p == NULL)

        return NULL;

    va_start(ap, fmt);

    size = vsnprintf(p, size, fmt, ap);

    va_end(ap);

    if (size < 0) {

        free(p);

        return NULL;

    }

    return p;
}

Если происходит обрезание в версиях glibc до 2.0.6, то это считается ошибкой.

СМОТРИТЕ ТАКЖЕ

printf(1), asprintf(3), puts(3), scanf(3), setlocale(3), strfromd(3), wcrtomb(3), wprintf(3), locale(5)

2019-03-06 GNU