C/printf: Różnice pomiędzy wersjami

Dodane 9605 bajtów ,  15 lat temu
W zasadzie wszystko od nowa - sprawdzane z draftem C99
(W zasadzie wszystko od nowa - sprawdzane z draftem C99)
===Deklaracja===
W pliku nagłówkowym [[C/Biblioteka standardowa/Indeks tematyczny#stdio.h|stdio.h]]:
:int printf (const char *format, ...);
 
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, ...)
 
W pliku nagłówkowym [[C/Biblioteka standardowa/Indeks tematyczny#stdarg.h|stdarg.h]]:
===Plik nagłówkowy===
:[[C/Biblioteka standardowa/Indeks tematyczny#stdio.h|stdio.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);
 
===Opis===
Funkcje formatują tekst zgodnie z podanym formatem opisanym poniżej. Funkcje printf i vprintf wypisują tekst na standardowe wyjście (tj. do stdout); fprintf i vfprintf do strumienia podanego jako argument; a sprintf, vsprintf, snprintf i vsnprintf zapisują go w podanej jako argument tablicy znaków.
:Funkcja wypisuje na standardowe wyjście tablicę znaków, na którą wskazuje ''format''.
 
Funkcje vprintf, vfprintf, vsprintf i vsnprintf różnią się od odpowiadających im funkcjom printf, fprintf, sprintf i snprintf tym, że zamiast zmiennej liczby argumentów przyjmują argument typu va_list.
 
Funkcje snprintf i vsnprintf różnią się od sprintf i vsprintf tym, że nie zapisuje do tablicy nie więcej niż <tt>size</tt> znaków (wliczając kończący znak '\0'). Oznacza to, że można je używać bez obawy o wystąpienie przepełnienia bufora.
 
===Argumenty===
:<tt>format</tt> - format, w jakim zostaną wypisane następne argumenty, zobacz [[C/Lista argumentów funkcji printf|Lista argumentów funkcji printf]].
:<tt>stream</tt> - strumień wyjściowy, do którego mają być zapisane dane
:następne argumenty - lista argumentów dowolnego z typów wbudowanych
:<tt>str</tt> - tablica znaków, do której ma być zapisany sformatowany tekst
:<tt>size</tt> - rozmiar tablicy znaków
 
===Format===
Format składa się ze zwykłych znaków (innych niż znak '%'), które są kopiowane bez zmian na wyjście oraz sekwencji sterujących, zaczynających się od symbolu procenta, po którym może nastąpić:
* dowolna liczba flag,
* opcjonalne określenie minimalnej szerokości pola,
* opcjonalne określenie precyzji,
* opcjonalne określenie rozmiaru argumentu,
* określenie formatu.
 
====Flagi====
W sekwencji możliwe są następujące flagi:
* '''-''' (minus) oznacza, że pole ma być wyrównane do lewej, a nie do prawej.
* '''+''' (plus) oznacza, że dane liczbowe zawsze poprzedzone są znakiem (plusem dla liczb nieujemnych lub minusem dla ujemnych).
* spacja oznacza, że liczby nieujemne poprzedzone są dodatkową spacją; jeżeli flaga plus i spacja są użyte jednocześnie to spacja jest ignorowana.
* '''#''' (''hash'') powoduje, że wynik jest przedstawiony w ''alternatywnej postaci'':
** dla formatu '''o''' powoduje to zwiększenie precyzji, jeżeli jest to konieczne, aby na początku wyniku było zero;
** dla formatów '''x''' i '''X''' niezerowa liczba poprzedzona jest ciągiem '''0x''' lub '''0X''';
** dla formatów '''a''', '''A''', '''e''', '''E''', '''f''', '''F''', '''g''' i '''G''' wynik zawsze zawiera kropkę nawet jeżeli nie ma za nią żadnych cyfr;
** dla formatów '''g''' i '''G''' końcowe zera nie są usuwane.
* '''0''' (zero) dla formatów '''d''', '''i''', '''o''', '''u''', '''x''', '''X''', '''a''', '''A''', '''e''', '''E''', '''f''', '''F''', '''g''' i '''G''' do wyrównania pola wykorzystywane są spacje zamiast spacji za wyjątkiem wypisywania wartości nieskończoność i NaN. Jeżeli obie flagi 0 i - są obecne to flaga zero jest ignorowana. Dla formatów '''d''', '''i''', '''o''', '''u''', '''x''' i '''X''' jeżeli określona jest precyzja flaga ta jest ignorowana.
 
====Szerokość pola i precyzja====
Minimalna szerokość pola oznacza ile najmniej znaków ma zająć dane pole. Jeżeli wartość po formatowaniu zajmuje mniej miejsca jest ona wyrównywana spacjami z lewej strony (chyba, że podano flagi, które modyfikują to zachowanie). Domyślna wartość tego pola to 0.
 
Precyzja dla formatów:
* '''d''', '''i''', '''o''', '''u''', '''x''' i '''X''' określa minimalną liczbę cyfr, które mają być wyświetlone i ma domyślną wartość 1;
* '''a''', '''A''', '''e''', '''E''', '''f''' i '''F''' - liczbę cyfr, które mają być wyświetlone po kropce i ma domyślną wartość 6;
* '''g''' i '''G''' określa liczbę cyfr znaczących i ma domyślną wartość 1;
* dla formatu '''s''' - maksymalną liczbę znaków, które mają być wypisane.
 
Szerokość pola może być albo dodatnią liczbą zaczynającą się od cyfry różnej od zera albo gwiazdką. Podobnie precyzja z tą różnicą, że jest jeszcze poprzedzona kropką. Gwiazdka oznacza, że brany jest kolejny z argumentów, który musi być typu int. Wartość ujemna przy określeniu szerokości jest traktowana tak jakby podano flagę '''-''' (minus).
 
====Rozmiar argumentu====
Dla formatów '''d''' i '''i''' można użyć jednego ze modyfikator rozmiaru:
* '''hh''' - oznacza, że format odnosi się do argumentu typu signed char,
* '''h''' - oznacza, że format odnosi się do argumentu typu short,
* '''l''' (el) - oznacza, że format odnosi się do argumentu typu long,
* '''ll''' (el el) - oznacza, że format odnosi się do argumentu typu long long,
* '''j''' - oznacza, że format odnosi się do argumentu typu intmax_t,
* '''z''' - oznacza, że że format odnosi się do argumentu typu będącego odpowiednikiem typu size_t ze znakiem,
* '''t''' - oznacza, że że format odnosi się do argumentu typu ptrdiff_t.
 
Dla formatów '''o''', '''u''', '''x''' i '''X''' można użyć takich samych modyfikatorów rozmiaru jak dla formatu '''d''' i oznaczają one, że format odnosi się do argumentu odpowiedniego typu bez znaku.
 
Dla formatu '''n''' można użyć takich samych modyfikatorów rozmiaru jak dla formatu '''d''' i oznaczają one, że format odnosi się do argumentu będącego wskaźnikiem na dany typ.
 
Dla formatów '''a''', '''A''', '''e''', '''E''', '''f''', '''F''', '''g''' i '''G''' można użyć modyfikatorów rozmiaru '''L''', który oznacza, że format odnosi się do argumentu typu long double.
 
Dodatkowo, modyfikator '''l''' (el) dla formatu '''c''' oznacza, że odnosi się on do argumentu typu wint_t, a dla formatu '''s''', że odnosi się on do argumenty typu wskaźnik na wchar_t.
 
====Format====
Funkcje z rodziny printf obsługują następujące formaty:
 
* '''d''', '''i''' - argument typu int jest przedstawiany jako liczba całkowita ze znakiem w postaci '''[-]ddd'''.
 
* '''o''', '''u''', '''x''', '''X''' - argument typu unsigned int jest przedstawiany jako nieujemna liczba całkowita zapisana w systemie oktalnym ('''o'''), dziesiętnym ('''u''') lub heksadecymalnym ('''x''' i '''X''').
 
* '''f''', '''F''' - argument typu double jest przedstawiany w postaci '''[-]ddd.ddd'''.
 
* '''e''', '''E''' - argument typu double jest reprezentowany w postaci '''[i]d.ddde+dd''', gdzie liczba przed kropką dziesiętną jest różna od zera, jeżeli liczba jest różna od zera, a '''+''' oznacza znak wykładnika. Format '''E''' używa wielkiej litery E zamiast małej.
 
* '''g''', '''G''' - argument typu double jest reprezentowany w formacie takim jak '''f''' lub '''e''' (odpowiednio '''F''' lub '''E''') zależnie od liczby znaczących cyfr w liczbie oraz określonej precyzji.
 
* '''a''', '''A''' - argument typu double przedstawiany jest w formacie '''[-]0xh.hhhp+d''' czyli analogicznie jak dla '''e''' i '''E''', tyle że liczba zapisana jest w systemie heksadecymalnym.
 
* '''c''' - argument typu int jest konwertowany do unsigned char i wynikowy znak jest wypisywany. Jeżeli podano modyfikator rozmiaru '''l''' argument typu wint_t konwertowany jest do wielobajtowej sekwencji i wypisywany.
 
* '''s''' - argument powinien być typu wskaźnik na char (lub wchar_t). Wszystkie znaki z podanej tablicy, aż do i z wyłączeniem znaku null są wypisywane.
 
* '''p''' - argument powinien być typu wskaźnik na void. Jest to konwertowany na serię drukowalnych znaków w sposób zależny od implementacji.
 
* '''n''' - argument powinien być wskaźnikiem na liczbę całkowitą ze znakiem, do którego zapisana jest liczba zapisanych znaków.
 
W przypadku formatów '''f''', '''F''', '''e''', '''E''', '''g''', '''G''', '''a''' i '''A''' wartość nieskończoność jest przedstawiana w formacie '''[-]inf''' lub '''[-]infinity''' zależnie od implementacji. Wartość NaN jest przedstawiana w postaci '''[-]nan''' lub '''[i]nan(''sekwencja'')''', gdzie '''sekwencja''' jest zależna od implementacji. W przypadku formatów określonych wielką literą również wynikowy ciąg znaków jest wypisywany wielką literą.
 
===Wartość zwracana===
Jeżeli funkcje zakończą się sukcesem zwracają liczbę znaków w tekście (wypisanym na standardowe wyjście, do podanego strumienia lub tablicy znaków) nie wliczając kończącego '\0'. W przeciwnym wypadku zwracana jest liczba ujemna.
:Liczba znaków wypisana na standardowym wyjściu.
 
Wyjątkami są funkcje snprintf i vsnprintf, które zwracają liczbę znaków, które zostałyby zapisane do tablicy znaków, gdyby była wystarczająco duża.
 
===Przykład użycia===
 
#include <stdio.h>
int main() {
int i = 4;
float f = 3.1415;
char *s = "Monty Python";
printf("i = %i\nf = %.1f\nWskaźnik s wskazuje na napis: %s\n", i, f, s);
return 0;
}
 
f = 3.1
Wskaźnik s wskazuje na napis: Monty Python
 
Funkcja formatująca ciąg znaków i alokująca odpowiednią ilość pamięci:
 
#include <stdarg.h>
#include <stdlib.h>
char *sprintfalloc(const char *format, ...) {
int ret;
size_t size = 100;
char *str = malloc(size);
if (!str) {
return 0;
}
for(;;){
va_list ap;
char *tmp;
va_start(ap, format);
ret = vsnprintf(str, size, format, ap);
va_end(ap);
if (ret<size) {
break;
}
tmp = realloc(str, (size_t)ret + 1);
if (!tmp) {
ret = -1;
break;
} else {
str = tmp;
size = (size_t)ret + 1;
}
}
if (ret<0) {
free(str);
str = 0;
} else if (size-1>ret) {
char *tmp = realloc(str, (size_t)ret + 1);
if (tmp) {
str = tmp;
}
}
return str;
}
 
===Uwagi===
Funkcje snprintf i vsnprintf nie były zdefiniowane w standardzie C89. Zostały one dodane dopiero w standardzie C99.
 
Biblioteka glibc do wersji 2.0.6 włącznie posiadała implementacje funkcji snprintf oraz vsnprintf, które były niezgodne ze standardem, gdyż zwracały -1 w przypadku, gdy wynikowy tekst nie mieścił się w podanej tablicy znaków.
 
{{TODO|Porównać ze standardem C89 i oznaczyć funkcjonalności wprowadzone dopiero w C99.}}
 
===Zobacz też===
:[[C/fprintf|fprintf]], [[C/scanf|scanf]], [[C/sprintf|sprintf]]
:[[C/Podstawowe procedury wejścia i wyjścia|Podstawowe procedury wejścia i wyjścia]]
279

edycji