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():
dprintf(), vdprintf():
Функции семейства 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.
За символом % может быть указано ноль или несколько следующих флагов:
Пять флагов, описанных выше, определены в стандарте C99. В стандарте Single UNIX Specification определён ещё один дополнительный флаг.
В glibc 2.2 добавлен ещё один флаг.
Необязательная строка из десятичных цифр (с первой цифрой, отличной от нуля) определяет минимальную ширину поля. Если преобразованное значение имеет меньшее количество знаков, чем ширина поля, то оно слева дополняется пробелами (или справа, если указан флаг выравнивания по левому краю). Вместо строки десятичных цифр можно указать «*» или «*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.
В SUSv3 определено всё вышеперечисленное, за исключением указанных как нестандартное расширение. В SUSv2 определены только модификаторы длины h (в hd, hi, ho, hx, hX, hn) и l (в ld, li, lo, lx, lX, ln, lc, ls) и L (в Le, LE, Lf, Lg, LG).
Не по стандарту реализации GNU считают ll и L синонимами, поэтому, например, можно написать llg (синоним стандартного Lg) и Ld (синоним стандартного lld). Такое использование не переносимо.
Символы, которые определены как типы преобразования. Типы преобразования и их значения:
При успешном выполнении данные функции возвращают количество напечатанных символов (не включая байт 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 |