Назва
printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - функції форматування виводу
Огляд
#include <stdio.h>
int printf(const char format, ...);
int fprintf(FILE stream, 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 vsprintf(char str, const char format, va_list ap);
int vsnprintf(char str, size_t size, const char *format, va_list ap);
Опис
Функції з сімейства printf створюють вивід відповідно формату, описаного нижче. Функції printf і vprintf пишуть свій вивід до stdout, стандартного потоку виводу; fprintf і vfprintf пишуть свій вивід до заданого їм потоку виводу; sprintf, snprintf, vsprintf і vsnprintf пишуть до символьного ланцюжка str.
Функції vprintf, vfprintf, vsprintf i vsnprintf еквівалентні функціям printf, fprintf, sprintf і snprintf, відповідно, за винятком того, що вони вживаються з va_list замість змінної кількості аргументів. Ці функції не викликають макросу va_end, тож значення ap буде невизначеним після виклику. Додатки повинні самі покликати va_end(ap) в кінці.
Ці вісім функцій здійснюють вивід відповідно до ланцюжка форматування, який описує як саме аргументи, що слідують один за одним (або аргументи, доступні завдяки засобам обробки змінної кількості аргументів stdarg(3)) перетворено для виводу.
Повернені значення
У випадку вдалого виконання, ці функції повертають кількість виведених знаків (виключаючи завершальний '\0', використовуваний для закінчення виводу ланцюжків). Функції snprintf і vsnprintf не записують більше ніж size байтів (завершальний '\0', включно). Якщо вивід урізано, завдяки цьому обмеженню, тоді поверненим значенням буде число знаків (без кінцевого '\0'), яке було би виведено як остаточний ланцюжок, якби було би достатньо місця. Таким чином, повернене значення, рівне size або більше, означає, що вивід урізано. (Подивіться також коментар у ПРИМІТКАХ.) Якщо відбулася помилка виводу, повертається від'ємне значення.
Формат форматувального ланцюжка
Форматувальний ланцюжок відповідає за зовнішній вигляд виводу. Він складається з нуля або більше директив: звичайних знаків (без %), які копійовано без змін до вивідного потоку і описувачі перетворення, кожному з яких відповідає один аргумент пізніше. Кожен описувач перетворення починається зі знаку % і закінчується літерою-вказівником перетворення, між якими можуть знаходитись (у наведеній послідовності) нуль або більше прапорців, необов'язковий вказівник ширини поля, необов'язковий вказівник точності і довжини.
Вимагається належна відповідність між аргументами (після переведення типу) й опусувачами перетворення. Типово, аргументи використовуються у заданому порядку, де *' у кожному описувачі перетворення запитує наступний аргумент (і відбудеться помилка, якщо вказано недостатньо аргументів). Ви можете також явно вказати, який аргумент взяти там де вимагається аргумент, записом
%m$' замість %' і
m$' замість `', де десяткове ціле m означає положення бажаного аргументу у списку аргументів; індексація починається з 1. Таким чином,
printf("%*d", width, num);
і
printf("%2$*1$d", width, num);
являються еквівалентними. Другий стиль нотації дозволяє повторні звернення до того самого аргументу. Стандарт C99 не включає використання $', яке було привнесено з Єдиної Специфікації Юнікса. Якщо використовується стиль з
$', його необхідно вживати скрізь для всіх перетворень з аргументом так само, як усіх вказівників ширини і точності, але його можна перемежовувати з форматом %%', який не бере жодних аргументів. Не може бути проміжків у кількості вказаних аргументів, використовуючи
$'; наприклад, якщо вказано аргумент 1 і 3, необхідно також десь у ланцюжку вказати й аргумент 2.
Для деяких числових перетворень використовується десятковий знак або знак угруповування тисяч. Ці знаки залежать від встановленої локалі для змінної середовища LC_NUMERIC. Локаль 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 результат завжди міститиме десяткову крапку, навіть якщо за нею не слідує жодних цифр (за звичайних обставин, десяткова крапка з'являється в цих перетвореннях тільки, якщо присутня десяткові числа). Для \fg\fP і 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 буде ігноровано. Для решти перетворень, поводження не є визначеним.
- : Перетворене значення вирівнюватиметься ліворуч у межах поля. (Стандартним є вирівнювання праворуч.) За винятком n-перетворень, значення заповнюватимуться пробілами з правої сторони, замість пробілів або нулів зліва, як звичайно. A переважить 0, якщо обидва задано.
. . : (пробіл) Добавить пробіл перед додатнім числом (або порожнім ланцюжком) у випадку перетворення зі знаком.
+ : Знак (+ або -) завжди добавлятиметься попереду числа у перетвореннях зі знаком. Стандартно, знак використовується тільки з від'ємними числами. Прапорець + переважить пробіл, якщо обидва задано.
П'ять вищенаведених прапорців визначено стандартом C. SUSv2 зазначено ще один прапорець:
, : У випадку десяткових перетворень i, d, u, f, F, g, або G, вивід поділятиметься на тисячі знаком поділу, якщо локаль включає такий. Майте на увазі, що багато версії gcc не розпізнають цієї опції і видадуть попередження. SUSv2 не включає %'F.
glibc 2.2 додало ще один знак прапорця: I У випадку десяткових перетворень 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-перетворень, або ж максимальне число символів, що буде виведено, для ланцюжкових перетворень s і S.
Модифікатор довжини
Тут "перетворення цілих" означає вказівники d, i, o, u, x або X.
hh : Наступне перетворення цілих відповідає аргументові, що являє собою ціле зі знаком або ціле без знаку, або наступне n-перетворення відповідає аргументу-покажчику на ціле зі знаком.
h : Наступне перетворення цілих відповідає короткому цілому або беззнаковому короткому цілому аргументові, або або наступне n-перетворення відповідає аргументу-покажчику на коротке ціле.
l : (англійська "л") Наступне перетворення цілих відповідає аргументові, що являє собою довге ціле або беззнакове довге ціле, або наступне \f\Bn\fP-перетворення відповідає покажчику на довге ціле, або наступне c-перетворення відповідає аргументові типу wint_t, або наступне s-перетворення відповідає аргументові типу wchat_t.
ll : (дві англійські "л") Наступне перетворення цілих відповідає аргументові, що являє собою довге-довге ціле або беззнакове довге-довге ціле, або ж наступне n-перетворення відповідає аргументу-покажчику на довге-довге ціле.
L : Наступні перетворення a, A, e, E, f, F, g або G відповідають аргументові, що являє собою довге подвійне. (C99 допускає %LF, тоді як SUSv2 - ні.)
q : ("quad". Тільки для BSD 4.4 і Linux libc5. Не використовуйте його.) Синонім ll.
j : Перетворення цілого, що відповідає аргументові типу intmax_t або uintmax_t.
z : Перетворення цілого, що відповідає аргументові типу size_t або ssize_t. (У Linux libc5 використовується Z для цього. Не вживайте його.)
t : Перетворення цілого, що відповідає аргументові типу ptrdiff_t.
SUSv2 знає тільки про модифікатори довжини h (у випадках hd, hi, ho, hx, hX, hn), модифікатор l (у випадках ld, li, lo, lx, lX, ln, lc, ls) а також L (у випадках Le, LE, Lf, Lg, LG).
Вказівники перетворення
Вказівниками перетворення називаються знаки, що вказують на тип застосовуваного перетворення. Ось їхній перелік:
d, i : Аргумент типу int перетворено до десяткового запису зі знаком. Точність, якщо така вказана, вказує мінімальне число цифр, що мусить з'явитися; якщо перетворене значення вимагає менше цифр, його заповнено з лівої сторони нулями. Стандартною точністю є 1. При виводі значення 0 зі вказаною точністю 0, нічого не з'явиться.
o, u, x, X : Беззнаковий аргумент типу int перетворено до беззнакової вісімкової (o), беззнакової десяткової (u) або беззнакової шістнадцяткової (x, X) нотації. Літери "abcdef" використовуються у випадку x, а "ABCDEF" у випадку X шістнадцяткового перетворення. Точність, якщо задано, вказуватиме мінімальну кількість цифр, що повинна з'явитись; якщо перетворене значення вимагатиме менше цифр, його буде заповнено нулями з лівої сторони. Стандартною точністю є 1. При виводі значення 0 зі вказаною точністю 0, нічого не з'явиться.
e, E : Аргумент типу подвійного округлено і виведено у стилі [-]d.dddedd, де буде одна цифра до десяткового знаку і кількість цифр після рівна вказівникові точності; якщо вказівник точності відсутній, використовуватиметься 6; якщо точність дорівнює нулю, десятковий знак не з'являтиметься. Перетворення з E використовує літеру "E" (замість "e") для представлення експоненти. Експонент завжди міститиме щонайменше дві цифри; якщо значення дорівнює нулю, експонент буде зображено як 00.
f, F : Аргумент типу подвійного округлено і перетворено у десяткове представлення в стилі [-]ddd.ddd, де кількість знаків після десяткового знаку дорівнює вказівникові точності. Якщо показник точності відсутній, використовуватиметься 6; якщо ж вказівник точності дорівнює нулю, десятковий знак не з'являтиметься. При появі десяткового знаку, принаймні одна цифра стоятиме попереду нього.
(SUSv2 не знає про F і обіцяє появу позначення для нескінченності і не-числа NaN. Стандарт C99 зазначив [-]inf' або
[-]infinity' для нескінченності і ланцюжок, що починається з nan' для не-числа NaN у випадку **f**-перетворення і, відповідно,
[-]INF' або [-]INFINITY' й
NAN*' - у випадку перетворення з F.)
g, G : Аргумент типу подвійного перетворено до стилю f або e (F і E, відповідно, для G). Вказівник точності зазначає число найважливіших цифр. Якщо вказівник точності відсутній, використовуватиметься 6 цифр; якщо точність дорівнює нулю, вона розглядатиметься як 1. e-стиль використовується, якщо експонент, після перетворення, менший за -4 або більший або дорівнює точності. Хвостові нулі вилучаються з дробової частини результату; десяткова точка з'явиться тільки, якщо за нею слідує принаймні одна цифра.
a, A : (C99; немає в SUSv2) У випадку a, аргумент типу подвійного перетворено до шістнадцяткового представлення (з використанням літер "abcdef") у стилі [-]0xh.hhhhpd; у випадку A, використовується префікс 0X, літери "ABSDEF" і розділювач експоненти P. Повинна бути одна шістнадцяткова цифра до десяткової точки і кількість цифр після дорівнює вказівникові точності. Стандартна точність повинна задовольняти правильне представлення числа, якщо правильне представлення в двійковій системі існує, у протилежному випадку, вона буде достатньо великою, щоб розрізняти значення типу подвійного. Цифру до десяткової точки не зазначено не ненормалізованих чисел і не-нулів, так само не зазначено для нормалізованих чисел.
c : Без модифікатору l (англійська "л"), аргумент типу int перетворено до беззнакового символу, unsigned char і, отриманий в результаті знак, виведено. При наявності модифікатору l, аргумент типу wint_t (широкий знак) перетворено до багатобайтової послідовності через виклик функції ?wcrtomb(3) і, отриманий у результаті знак виведено.
s : Без модифікатору l (англійська "л"): очікується, що аргумент типу const char * є покажчиком на масив знаків (покажчик на ланцюжок). Знаки з цього масиву виводяться аж до (не включаючи) завершуючого знаку NULL; якщо задано точність, виводиться не більше вказаного числа символів. З вказівником точності нульовий знак може бути відсутнім; якщо вказівника точності немає або він більший за розмір масиву, останній повинен містити завершувальний NULL.
З модифікатором l: очікується, що аргумент типу wchar_t * є покажчиком на масив широких знаків. Широкі знаки з масиву перетворено на багатобайтові знаки (кожний, шляхом виклику функції ?wcrtomb(3)), аж до завершуючого широкого знаку NULL, включно). Отримані в результаті багатобайтові знаки виводяться до (але не включаючи) завершувального NULL. Якщо задано точність, виводиться не більше вказаного числа символів, але не буде виведено неповного багатобайтового знаку. Зауважте, що точність вказує на кількість виведених байтів, а не широких символів. Масив повинен містити кінцевий широкий NULL, хіба задано точність і її значення менше за кількість байтів масиву.
C : (Немає в C99, тільки SUSv2) Синонім lc. Не використовуйте.
S : (Немає в C99, тільки SUSv2) Синонім ls. Не використовуйте.
p : Аргумент типу void * виводиться у шістнадцятковому представленні (так ніби вжито %#x або %#lx).
n : Кількість виведених до цих пір знаків збережено у ціле, на яке вказує аргумент, що є покажчиком типу int * (або варіантом цього). Перетворення аргументів не відбувається.
% : Виводиться %. Перетворення аргументів не відбувається. Повна форма: `%%'.
Приклади
Виведе pi з точністю 5:
#include <math.h>
#include <stdio.h>
fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));
Виводить дату і час у формі "Sunday, July 3, 10:02", де день тижня і місяць - покажчики на ланцюжки:
#include <stdio.h>
fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",
weekday, month, day, hour, min);
там де формат залежить від локалі, можна змінити аргументи. Зі значеннями
"%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, ...) {
/* Напевне, нам потрібно більш за 100 байтів. */
int n, size = 100;
char *p;
va_list ap;
if ((p = malloc (size)) == NULL)
return NULL;
while (1) {
/* Спробуємо записати у відведене місце. */
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
va_end(ap);
/* Якщо це спрацювало, повернути ланцюжок. */
if (n > -1 && n < size)
return p;
/* У протилежному випадку, додамо місця і *
* спробуємо знову. */
if (n > -1) /* glibc 2.1 */
size = n+1; /* трохи більше */
else /* glibc 2.0 */
size *= 2; /* у два рази більше */
if ((p = realloc (p, size)) == NULL)
return NULL;
}
}
Примітки
Втілення функцій snprintf і vsnprintf, які ви знайдете в glibc, відповідає стандартові C99, тобто поводяться так, як описано вище, починаючи з glibc 2.1. Попередньо до glibc 2.0.6, вони повертали -1, якщо вивід було урізано.
Відповідність стандартам
Функції fprintf, printf, sprintf, vprintf, vfprintf і vsprintf відповідають ANSI X3.159-1989 ("ANSI C") і ISO/IEC 9899:1999 ("ISO C99"). Функції snprintf і vsnprintf відповідають стандартові ISO/IEC 9899:1999.
Стосовно поверненого значення snprintf, SUSv2 і C99 перечать одне одному: якщо snprintf викликано з size=0, SUSv2 обумовлює повернення невизначеного значення, меншого за 1, тоді як C99 дозволяє ланцюжку бути NULL, у цьому випадку, і повернене значення (як звичайно) дорівнюватиме кількості знаків, яку було би виведено у випадку, якби ланцюжок був би достатньої довжини.
Linux libc4 знає про п'ять стандартних прапорців C. Знає також про модифікатори довжини h, l і L і перетворення cdeEfFgGinopsuxX, де F є синонімом f. На додаток, бібліотека розпізнає D, O, U, як синоніми ld, lo та lu. (Це недобре і спричинило серйозні помилки пізніше, коли підтримка %D зникла.) Не розпізнаються, залежні від локалі, десяткові розділювачі, так само як розділювачі тисяч, NaN, нескінченість, %m$ або *m$.
Linux libc5 знає про п'ять стандартних прапорців C а також прапорець ', локаль, %m$ та *m$. Вона розпізнає модифікатори довжини h, l, L, Z, q, але приймає L та q для обох довгих подвійних і довгих-довгих цілих (це є помилкою). libc5 не розпізнає більше FDOU, але додала новий знак перетворення m, який виводить strerror(errno).
glibc 2.0 додала знаки перетворення C й S.
glibc 2.1 додала модифікатори довжини hh, j, t, z, а також знаки перетворення a, A.
glibc 2.2 додала знак перетворення F з семантикою C99, а також прапорець I.
Історія
Unix V7 визначає три функції: printf, fprintf і sprintf і має прапорець -, ширину або точність *, модифікатор довжини l і перетворення doxfegcsu разом з D, O, U, X, як синоніми ld, lo, lu, lx. Це залишається дійсним у BSD 2.9.1, але BSD 2.10 має прапорці #, + й <пробіл> і більше не згадує D, O, U, X. BSD 2.11 має vprintf, vfprintf, vsprintf і застерігає не використовувати D, O, U, X. BSD 4.3 Reno додало прапорець , модифікатори довжини h із L і перетворення n, p, E, G, X (з сучасним значенням) і відкинула D, O, U. BSD 4.4 ввела функції snprintf і vsnprintf і модифікатор довжини q. FreeBSD має також функції asprintf і vasprintf, які відводять достатньо великий буфер для sprintf. У glibc існують функції dprintf і vdprintf, які здійснюють запис до дескриптору файлу замість потоку.
Вади
Оскільки sprintf і vsprintf передбачають взаємодію з ланцюжками довільної довжини, необхідно бути обережним, щоб не переповнити дійсний простір; цього, часто, неможливо бути певним. Зауважте, що довжина отриманого ланцюжка може бути локалезалежною і важко передбачуваною. Використовуйте snprintf і vsnprintf натомість (або asprintf і vasprintf).
Linux libc4.[45] не має snprintf, зате включає бібліотеку libbsd, яка містить snprintf, еквівалентну sprintf, тобто таку, що ігнорує аргумент розміру. Таким чином, використання snprintf з ранніми версіями libc4 призводить до серйозних проблем з небезпекою.
Код на кшталт printf(foo) частіше вказує на помилку, оскільки foo може включати знак %. Якщо foo походить з незахищеного користувацького вводу, вона може містити %n, спричиняючи запис до пам'яті і діру у захисті.
Дивіться також
printf(1), ?asprintf(3), ?dprintf(3), ?wcrtomb(3), ?wprintf(3), scanf(3), ?locale(5)