printf – rodzinafunkcji służących do tworzenia i zapisywania tekstu na podstawieszablonu i zestawuargumentów, które są w ten szablon wstawiane.
Funkcje grupyprintf zostały stworzone na potrzeby językaC.Obecnie są dostępne również dla wielu innychjęzyków programowania.
| Zobacz podręcznik w Wikibooks:C –printf |
W C występuje wiele funkcji grupyprintf. Różnią się one jedynie sposobem przekazywania argumentów, znaczeniem kodu zwrotnego (który w zwykłymprintfie zwykle jest pomijany) i tym, co robi się z wygenerowanym tekstem.
Funkcje, które pojawiły się we wczesnychUniksach:
int printf (const char *format, ...); – wygenerowany tekst pisany jest nastandardowe wyjście.int fprintf (FILE *stream, const char *format, ...); – wygenerowany tekst pisany jest do strumieniastreamint sprintf(char *str, const char *format, ...); – wygenerowany tekst jest zapisywany do buforastr. Ponieważ istnieje niebezpieczeństwo wystąpieniaprzepełnienia bufora, należy rozsądnie stosować tę funkcję.WBSD 2.11 pojawiły się wersje dla argumentów przekazywanych przezstdarg:
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);WBSD 4.4 pojawiła się funkcja :
int snprintf(char *str, size_t size, const char *format, ...); – to samo cosprintf, tylko że zapisuje co najwyżejsize znaków (wliczając w to końcowe\0), dzięki czemu jest o wiele bezpieczniejsza.int vsnprintf(char *str, size_t size, const char *format, va_list ap);WFreeBSD iGNUlibc są obecne też (niestandardowe)
int asprintf(char **strp, const char *fmt, ...);int vasprintf(char **strp, const char *fmt, va_list ap);które same alokują pamięć pod tekst.Jest to najbezpieczniejsza funkcjaprintf pisząca do pamięci, jednak nie jest standardowa i może być trochę wolniejsza.
WGNUlibc dodatkowo są też obecne:
int dprintf(int fd, const char *format, ...);int vdprintf(int fd, const char *format, va_list ap);piszące do deskryptora zamiast do strumienia.
Istnieją też odpowiedniki dla szerokich znaków:
int wprintf(const wchar_t *format, ...);int fwprintf(FILE *stream, const wchar_t *format, ...);int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...);int vwprintf(const wchar_t *format, va_list args);int vfwprintf(FILE *stream, const wchar_t *format, va_list args);int vswprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, va_list args);W wielu innych językach występują funkcjeprintf isprintf (która wbrew nazwie prawie wszędzie sama alokuje pamięć).
Przykłady:
printf "%d+%d=%d\n" 2 2 $[2+2]printf ("%d+%d=%d\n",2,2,2+2);fmt.Printf("%d+%d=%d\n", 2, 2, 2 + 2)System.out.printf("%d+%d=%d\n", 2, 2, 2 + 2);String s = String.format("%d+%d=%d\n", 2, 2, 2 + 2); System.out.print(s);fprintf('%d+%d=%d\n',2,2,2+2)sprintf('%d+%d=%d\n',2,2,2+2)writeln(format('%d+%d=%d'+#13,[2,2,2+2]));Printf.printf "%d+%d=%d\n" 2 2 (2+2);;let a = Printf.sprintf "%d+%d=%d\n" 2 2 (2+2);; Printf.printf "%s" a;;printf ("%d+%d=%d\n",2,2,2+2)$s=sprintf ("%d+%d=%d\n",2,2,2+2); print $sprintf("%d+%d=%d\n", 2, 2, 2 + 2);write o funkcjonalności analogicznej doprintf. Funkcja alokująca zmienną tekstową jest jednak nazwanasprintf:write ("%d+%d=%d\n", 2,2,2+2);s = sprintf ("%d+%d=%d\n", 2,2,2+2); write (s);%, z lewej strony którego jest format a z prawej lista argumentówprint("%d+%d=%d\n"%(2,2,2+2))s = "%d+%d=%d\n"%(2,2,2+2); print(s)printf ("%d+%d=%d\n",2,2,2+2)s=sprintf ("%d+%d=%d\n",2,2,2+2); print ss="%d+%d=%d\n" % 2,2,2+2; print sprintf("%d+%d=%d\n", 2, 2, 2 + 2)val s = "%d+%d=%d\n".format(2, 2, 2 + 2); print(s)Szablon to zwykły tekst zawierający pola do uzupełniania. Pole zaczyna się od znaku%,potem mogą wystąpić modyfikatory, a na koniec pojedynczy znak typu pola. Znak% pisze się%%.
Należy zauważyć, że znaki specjalne postaci\X nie mają nic wspólnego zprintfem i są obsługiwane przez kompilatorC w czasie kompilacji lubinterpreter w przypadku niektórych innych języków.
Zestaw dozwolonych pól jest różny zależnie od języka i standardu.Krótki przegląd częściej stosowanych pól:
%d – liczba całkowita ze znakiem w formacie dziesiętnym%i – synonim dla%d%x – liczba całkowita bez znaku w formacie szesnastkowym, z użyciem małych liter%X – liczba całkowita bez znaku w formacie szesnastkowym, z użyciem wielkich liter%o – liczba całkowita bez znaku w formacie oktalnym%u – liczba całkowita bez znaku w formacie dziesiętnym%e –liczba zmiennoprzecinkowa w zapisie naukowym (1.2345e+2)%E – liczba zmiennoprzecinkowa w zapisie naukowym (1.2345E+2)%f – liczba zmiennoprzecinkowa typudouble (float jest automatycznie konwertowany) w zapisie dziesiętnym (123.45)%c – liczba całkowita jest konwertowana na bajt o danej wartości%s – łańcuch tekstowy%p –wskaźnik%n – do argumentu zapisywana jest liczba dotychczas zapisanych znaków. Istnienie tego pola prowadzi do dużego niebezpieczeństwa (umożliwia przeprowadzenie niektórych wariantów ataku typuformat string) a nie jest zbyt przydatne w praktyce.Niektóre pola z modyfikatorami:
%ld – liczba całkowita typulong ze znakiem w formacie dziesiętnym%lld – liczba całkowita typulong long ze znakiem w formacie dziesiętnym – w większości popularnych kompilatorów (np. gcc)%llu – liczba całkowita typulong long bez znaku w formacie dziesiętnym – jw.%I64d – liczba całkowita typulong long ze znakiem w formacie dziesiętnym – używane w niektórych kompilatorach (np. Dev-cpp)%zd – liczba całkowita typusize_t ze znakiem w formacie dziesiętnym%hd – liczba całkowita typushort ze znakiem w formacie dziesiętnym% d – liczba całkowita ze znakiem w formacie dziesiętnym, w przypadku liczby dodatniej przed liczbą dać spację%+d – liczba całkowita typushort ze znakiem w formacie dziesiętnym, zawsze drukować znak%04d – liczba całkowita, uzupełniana zerami do czterech miejsc.%lf – liczba zmiennoprzecinkowa typudouble w zapisie dziesiętnym (123.456789)%[^\n]s – w rodziniesprintf wczytanie całej linii bez znaków kończących linię (CR, LF).Z użyciem funkcji z rodziny printf wiążą się dwie podstawowe grupy zagrożeń bezpieczeństwa:
%n. Najczęstszą przyczyną takiej podatności jest skorzystanie przez programistę z konstrukcjiprintf(zmienna); zamiastprintf("%s",zmienna);.*sprintf (a także nieprawidłowo użyta*snprintf) może przepełnić bufor przeznaczony przez programistę na zachowanie wyniku tej operacji, tym samym prowadząc do nadpisania struktur sterujących w pamięci procesu i przejęcie nad nim kontroli przez osobę trzecią.Dodatkowo, pewne scenariusze ataków mogą pojawiać się, gdy dochodzi do niezgodności między budową szablonu a faktycznymi parametrami przekazanymi funkcji*printf – na przykład gdy parametrów jest mniej niż pól w szablonie, albo wartości liczbowe przekazywane są w miejsce wskaźników. Błędy tego typu zwykle prowadzą jednak do nieprawidłowego działania programu i zostają wykryte przez programistę szybciej, niż dwie wymienione wyżej klasy.
Większość nowych języków udostępnia funkcje typuprintf, choć zwykle dostępne są też inne mechanizmy, np. wPerlu można wpisywać bezpośrednio w łańcuch tekstowy nazwy zmiennych – np.$x=2;$y=2;$z=2+2; print "$x+$y=$z",a wRuby nawet całe wyrażenia –print "#{2}+#{2}=#{2+2}\n".
W platformie.NET istnieje podobna funkcjaString.Format("{0}+{1}={2}\n", 2, 2, 2 + 2), która dodatkowo umożliwia łatwą zmianę kolejności użycia argumentów.
Niektóre języki, np.Ada, celowo nie posiadają funkcji tego typu.Są one tu praktycznie niemożliwe do implementacji ze względu na zbyt silną kontrolę systemu typów.
Argumenty za:
Przeciw: