Manpages

NAAM

printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf − geformateerde uitvoer conversie

SAMENVATTING

#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);

BESCHRIJVING

De functies in de printf familie produceren uitvoer volgens een format zoals onder beschreven. De functies printf en vprintf schrijven uitvoer naar stdout, de standaard uitvoer stroom; fprintf en vfprintf schrijven uitvoer naar de gegeven uitvoer stroom; sprintf, snprintf, vsprintf en vsnprintf schrijven naar de karakter string str.

De functies vprintf, vfprintf, vsprintf, vsnprintf zijn vergelijkbaar met respectievelijk de functies printf, fprintf, sprintf, snprintf; het verschil is dat ze worden aangeroepen met een va_list inplaats van een variabel aantal argumenten. Deze functies roepen de va_end macro niet aan. Daarom is de waarde van ap ongedefinieerd na de aanroep. De toepassing zou naderhand zelf va_end(ap) moeten aanroepen.

Deze acht functies schrijven de uitvoer onder controle van een format string, die specificeerd hoe opeenvolgende argumenten worden omgezet voor uitvoer. Deze argumenten kunnen ook via de mogelijkheden van stdarg(3) om argumenten van variable lengte te geven, meegegeven zijn.

Teruggeef Waarde
Deze functies geven het aantal afgedrukte karakters terug (de afsluitende ’\0’, gebruikt om de uitvoer van strings te beëindigen, wordt niet meegeteld). snprintf En vsnprintf schrijven niet meer dan size bytes (inclusief de afsluitende ’\0’), en geven -1 terug als de uitvoer werd afgekapt door deze limiet. (Zo was het tot glibc 2.0.6. Sinds glibc 2.1 volgen deze functies de C99 standaard en geven ze het aantal karakters (exclusief de afsluitende ’\0’) dat geschreven zou zijn naar de uiteindelijke string als genoeg ruimte voorhanden was geweest.)

Vorm van de formatstring
De formatstring is een karakterstring, beginnend en eindigend in zijn initiële "shift state", als die er is. De vormstring bestaat uit nul of meer aanwijzingen: normale karakters (niet %), die onveranderd naar de uitvoer stroom worden gekopiërd; en conversie specificaties, die elk zorgen dat nul of meer opeenvolgende argumenten gepakt worden. Elke conversie specificatie wordt begonnen met het karakter %, en eindigt met een conversie specificatie. Daar tussenin mogen (in deze volgorde) nul of meer vlaggen aanwezig zijn, een optionele minimum veldbreedte, een optionele precisie en een optionele lengte aanpasser.

De argumenten moeten correct overeenkomen (na type promotie) met de conversie specificatie. Standaard worden de argumenten in de gegeven volgorde gebruikt, waarbij elke ’*’ en elke conversie specificatie vraagt om het volgende argument (en het is een fout als een onvoldoende aantal argumenten zijn gegeven). Men kan ook expliciet opgeven welk argument genomen zal worden, op elke plaats waar een argument vereist is, door ’%m$’ te schrijven inplaats van ’%’ en ’*m$’ inplaats van ’*’, waar het decimale hele getal m de positie in de argumenten lijst van het gewenst argument bepaald, genummerd vanaf 1. Dus,

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

en

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

zijn gelijk. De tweede stijl laat herhaaldelijke referenties naar hetzelfde argument toe. De C99 standaard specificeert de ’$’ stijl niet; die komt van de Single Unix Specification. Als de ’$’ stijl wordt gebruikt, dan moet die gebruikt worden voor alle conversies die een argument meekrijgen en alle breedte en precisie argumenten. De stijl mag echter gemengd worden met ’%%’ vormen die geen argument gebruiken. Er mogen geen gaten zitten in de nummering van de argumenten die met ’$’ gespecificeerd worden; bijvoorbeeld, als argumenten 1 en 3 gespecificeerd zijn, dan moet ook argument 2 ergens in de formatstring gespecificeerd zijn.

Voor sommige numerieke conversies wordt een breuk-karakter (’decimale komma’) of duizendtallen-scheidingskarakter gebruikt. Het feitelijk gebruikte karakter hangt af van het LC_NUMERIC deel van de ’localiteit’. De POSIX localiteit gebruikt ’.’ als breuk-karakter, en heeft geen duizendtallen-scheidingskarakter. Dus:

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

resulteert in ’1234567.89’ in de POSIX localiteit, in ’1234567,89’ in de nl_NL localiteit, en in ’1.234.567,89’ in de da_DK localiteit.

De vlag karakters
Het karakter % wordt gevolgd door nul of meer van de volgende vlaggen:

#

De waarde moet omgezet worden naar een ’’alternatieve vorm’’. Voor o conversies betekent dat dat het eerste karakter van de uitvoerstring nul wordt (door een 0 ervoor te zetten als het niet al nul was). Voor x en X conversies, heeft een niet−nul resultaat de string ’0x’ (’0X’ voor X conversies) ervoor gezet. Voor a, A, e, E, f, g, en G omzettingen zal het resultaat altijd een decimale punt hebben, zelfs als er geen cijfers op volgen (gewoonlijk verschijnt een decimale punt alleen in de resultaten van deze conversies als er een cijfer op volgt). Voor g en G conversies worden nakomende nullen niet verwijderd van het resultaat, wat anders wel het geval zou zijn. Voor andere omzettingen is het resultaat onbepaald.

0

De waarde moet met nullen aangevuld worden. Voor d, i, o, u, x, X, a, A, e, E, f, F, g, en G omzettingen wordt de geconverteerde waarde links met nullen aangevuld, in plaats van met witruimte. Als de 0 en vlaggen allebei gezet zijn, dan wordt de 0 vlag genegeerd. Als een precisie gegeven is met een numerieke omzetting (d, i, o, u, x, en X), dan wordt de 0 vlag genegeerd. Voor andere conversies is het gedrag onbepaald.

De geconverteerde waarde wordt links uitgelijnd op de veldgrens. (Normaal wordt rechts uitgelijnd.) De geconverteerde waarde wordt aan de rechterkant aangevuld met witruimte, in plaats van links met witruimte of nullen (dit geldt niet voor n conversies). Een heeft voorrang op een 0 als beide gegeven zijn.

´ ´

(een spatie) Een spatie gaat vooraf aan een positief getal (of lege string) dat gegeven wordt na een conversie met teken.

+

Een teken (+ of -) wordt altijd geplaatst voor een getal dat door een conversie met teken gegeven wordt. Normaal gesproken wordt een teken alleen gebruikt voor negatieve getallen. Een + heeft voorrang op een spatie als beiden gebruikt worden.

De vijf vlagkarakters boven zijn gedefinieerd in de C standaard. De SUSv2 standaard geeft nog één extra vlagkarakter.

Voor decimale conversie (i, d, u, f, F, g, G) moet de uitvoer gegroepeerd worden met duizendtallen scheidingstekens, als de localiteit die opgeeft. Merk op dat veel versies van gcc deze optie niet kunnen lezen, en een waarschuwing zullen geven. SUSv2 geeft %’F niet.

glibc 2.2 geeft nog een vlagkarakter.

I

Voor decimale integer conversie (i, d, u) gebruikt de uitvoer de alternatieve uitvoer cijfers van de localiteit, als die er is (bijvoorbeeld arabische cijfers). Echter, er zijn geen localiteit definities met zulke outdigits meegegeven.

De veldbreedte
Een optionele decimale cijfer string (met het eerste cijfer niet-nul) dat een minimale veldbreedte opgeeft. Als de geconverteerde waarde minder karakters dan de veldbreedte heeft, dan wordt die links aangevuld met spaties (of rechts, als de links-uitlijnen vlag gegeven is). In plaats van een decimale cijfer string kan men ook ’*’ of ’*m$’ schrijven (voor een decimale integer m) op aan te geven dat de veldbreedte gegeven is in het volgende argument, of in het m-de argument, respectievelijk, dat van type int moet zijn. Een negatieve veldbreedte wordt gelezen als een ’-’ vlag, gevolgd door een positieve veldbreedte. In geen geval leidt een niet-bestaande of kleine veldbreedte tot afkappen van een veld; als het resultaat van een conversie breder is dan de veldbreedte, dan wordt het veld breder gemaakt om het resultaat te kunnen bevatten.

De precisie
Een optionele precisie, in de vorm van een punt (’.’) gevolgd door een optionele decimale cijferstring. In plaats van een decimale cijferstring kan men ’*’ of ’*m$’ schrijven (waarbij m een decimale integer is) om aan te geven dat de precisie gegeven is in respectievelijk het volgende argument of het m-de argument, wat van type int moet zijn. Als de precisie gegeven is als slechts ’.’, of als de precisie negatief is, dan wordt dit gelezen als precisie nul. Dit geeft het minimum aantal cijfers dat voor d, i, o, u, x, en X conversies moet voorkomen, het aantal cijfers dat na het radix karakter moet voorkomen voor a, A, e, E, f, en F conversies, het maximum aantal significante cijfers voor g en G conversies, of het maximum aantal karakters dat afgedrukt moet worden van een string voor s en S conversies.

De lengteaanpasser
Met ’integer conversie’ wordt hier d, i, o, u, x, of X conversie bedoeld.

hh

Een volgende integer conversie correspondeert met een signed char of unsigned char argument, of een volgende n conversie correspondeert met een pointer naar een signed char argument.

h

Een volgende integer conversie correspondeert met een short int of unsigned short int argument, of een volgende n conversie correspondeert met een pointer naar een short int argument.

l

(el) Een volgende integer conversie correspondeert met een long int of unsigned long int argument, of een volgende n conversie correspondeert met een pointer naar een long int argument, of een volgende c conversie correspondeert met een wint_t argument, of een volgende s conversie correspondeert met een pointer naar een wchar_t argument.

ll

(el-el). Een volgende integer conversie correspondeert met een long long int of unsigned long long int argument, of een volgende n conversie correspondeert met een pointer naar een long long int argument.

L

Een volgende a, A, e, E, f, F, g, of G conversie correspondeert met een long double argument. (%LF wordt toegestaan door C99, maar niet door SUSv2.)

q

(’quad’. Alleen bij BSD 4.4 en Linux libc5 . Niet gebruiken.) Dit is een synoniem voor ll.

j

Een volgende integer conversie correspondeert met een intmax_t of uintmax_t argument.

z

Een volgende integer conversie correspondeert met een size_t of ssize_t argument. (Linux libc5 heeft Z met deze betekenis. Niet gebruiken.)

t

Een volgende integer conversie correspondeert met een ptrdiff_t argument.

SUSv2 kent alleen de lengte aanpassers h (in hd, hi, ho, hx, hX, hn) en l (in ld, li, lo, lx, lX, ln, lc, ls) en L (in Le, LE, Lf, Lg, LG).

De conversie specificator
Een karakter dat aangeeft welk type van conversie moet worden toegepast. De conversie specificatoren en hun betekenis zijn:

d,i

Het int argument wordt geconverteerd naar decimale notatie met teken. De precisie, als die er is, geeft het minimum aantal cijfers dat moet voorkomen; als de geconverteerde waarde minder cijfers nodig heeft, dan wordt het links met nullen aangevuld. De standaard precisie is 1. Als 0 wordt afgedrukt met een expliciete precisie 0, dan is de uitvoer leeg.

o,u,x,X

Het unsigned int argument wordt geconverteerd naar octaal zonder teken. (u), of hexadecimaal zonder teken (x en X) notatie. De letters abcdef worden gebruikt voor x conversies; de letters ABCDEF worden gebruikt voor X conversies. De precisie, als die er is, geeft het minimum aantal cijfers dat voor moet komen; als de geconverteerde waarde minder cijfers nodig heeft, dan wordt het links met nullen aangevuld. De standaard precisie is 1. Als 0 wordt afgedrukt met een expliciete precisie 0, dan is de uitvoer leeg.

e,E

Het double argument wordt afgerond en geconverteert in de stijl [−]d.ddde±dd waar er één cijfer voor het decimale-punt karakter is, en het aantal cijfers erna gelijk is aan de precisie; als de precisie ontbreekt, dan wordt die als 6 genomen; als de precisie nul is, dan verschijnt er geen decimale-punt karakter. Een E conversie gebruikt de letter E (in plaats van e) om de exponent aan te geven. De exponent bevat altijd ten minste twee cijfers; als de waarde nul is, dan is de exponent 00.

f,F

Het double argument wordt afgerond en geconverteerd naar decimale notatie in de stijl [−]ddd.ddd, waar het aantal cijfers na het decimale-punt karakter gelijk is aan de precisie specificatie. Als de precisie ontbreekt, dan wordt die als 6 genomen; als de precisie expliciet nul is, dan verschijnt er geen decimale-punt karakter. Als er een decimale punt verschijnt, dan komt er tenminste één cijfer vóór.

(SUSv2 kent geen F en zegt dat karakterstring representaties voor oneindig en NaN beschikbaar zouden kunnen komen. De C99 standaard specificeert ’[-]inf’ of ’[-]infinity’ voor oneindig, en een string, beginnend met ’nan’ voor NaN, in het geval van f conversie, en ’[-]INF’ of ’[-]INFINITY’ of ’NAN*’ in het geval van F conversie.)

g,G

Het double argument wordt geconverteerd in stijl f of e (of F of E voor G conversies). De precisie specificeert het aantal significante cijfers. Als de precisie ontbreekt, dat worden 6 cijfers gegeven; als de precisie nul is, dan wordt het behandeld als 1. Stijl e wordt gebruikt als de exponent van de conversie minder dan −4 is of groter dan of gelijk aan de precisie. Nullen aan het eind worden verwijderd van het fractionele deel van het resultaat; een decimale punt verschijnt alleen als die gevolgd wordt door ten minste één cijfer.

a,A

(C99; niet in SUSv2) Voor a conversie, wordt het double argument geconverteerd naar hexadecimale notatie (gebruikmakend van de letters abcdef) in de stijl [-]0xh.hhhhp±d; voor A conversie wordt de prefix 0X, de letters ABCDEF, en de exponent scheider P gebruikt. Er is één hexadecimaal cijfer voor de decimale punt, en het aantal cijfers erna is gelijk aan de precisie. De standaard precisie is genoeg voor een exacte representatie van de waarde als een exacte binaire representatie bestaat; anderzijds is die groot genoeg om waarden van type double te kunnen onderscheiden. Het cijfer voor de decimale punt is onbepaald voor niet-genormaliseerde getallen, en niet-nul maar verder onbepaald voor genormaliseerde getallen.

c

Als er geen l aanpasser is, dan wordt het int argument geconverteerd naar een unsigned char; het resulterende karakter wordt dan geschreven. Als er een l aanpasser is, dan wordt het wint_t (breed karakter) argument geconverteerd naar een multibyte rij door een aanroep van de wcrtomb functie, met een conversie status in de initiële status; de resulterende byte wordt dan geschreven.

s

Als er geen l aanpasser is: Het const char * argument wordt aangenomen een pointer naar een rij van karaktertype (pointer naar een string) te zijn. Karakters van de rij worden geschreven tot aan (en zonder) een afsluitend NUL karakter; als een precisie gegeven is, dan worden er niet meer dan het aangegeven getal geschreven. Als een precisie gegeven is, dan hoeft er geen null karakter te zijn; als de precisie niet gegeven is, of groter is dan de maat van de rij, dan moet de rij een afsluitend NUL karakter bevatten.

Als er een l aanpasser is: Van het const wchar_t * wordt aangenomen dat het een pointer naar een rij van brede karakters is. Brede karakters van de rij worden geconverteerd naar multibyte karakters (ieder door een aanroep van de wcrtomb functie, met een conversie status beginnend in de initiële status vóór het eerste brede karakter), tot aan en met een afsluitend null breed karakter. De resulterende multibyte karakters worden geschreven tot aan (en zonder) de afsluitende null byte. Als een precisie gegeven is, dan worden niet meer bytes dan het aangegeven getal geschreven; echter, er worden geen gedeeltelijke multibyte karakters geschreven. Merk op dat de precisie het aantal geschreven bytes bepaald, niet het aantal brede karakters of screen positions. De rij moet een afsluitend null breed karakter bevatten, tenzij een precisie gegeven is, en de rij zo klein is dat het aantal geschreven bytes er voorbij gaat voordat het einde van de rij bereikt is.

C

(Niet in C99, wel in SUSv2.) Synoniem voor lc. Niet gebruiken.

ls .

Niet gebruiken.

p

Het void * pointer argument is afgedrukt in hexadecimaal (net als bij %#x of %#lx).

n

Het aantal karakters tot nog toe geschreven wordt opgeslagen in de integer aangegeven door het int * (of variant) pointer argument. Er wordt geen argument geconverteerd.

%

Een ’%’ wordt geschreven. Er wordt geen argument geconverteerd. De volledige conversie specificatie is ’%%’.

VOORBEELDEN

Om pi af te drukken in vijf decimalen:

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

Om een datum en tijd in de vorm ’Sunday, July 3, 10:02’, waar weekday en maand pointers naar strings zijn:

#include <stdio.h>
fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",
weekday, month, day, hour, min);

In veel landen wordt de dag-maand-jaar volgorde gebruikt. Daarom moet een geinternationaliseerde versie de argumenten af kunnen drukken in een volgorde die gespecificeerd wordt door het format:

#include <stdio.h>
fprintf(stdout, format,
weekday, month, day, hour, min);

waar format afhangt van localiteit, en de argumenten zou kunnen permuteren. Met de waarde

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

zou men ’Sonntag, 3. Juli, 10:02’ kunnen krijgen.

Om een voldoende grote string te alloceren en ernaar af te drukken (correcte code voor zowel glibc 2.0 als glibc 2.1):

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *
make_message(const char *fmt, ...) {
/* Guess we need no more than 100 bytes. */
int n, size = 100;
char *p;
va_list ap;
if ((p = malloc (size)) == NULL)
return NULL;
while (1) {
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
return p;
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n+1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if ((p = realloc (p, size)) == NULL)
return NULL;
}
}

ZIE OOK

printf(1), wcrtomb(3), wprintf(3), scanf(3), locale(5)

VOLDOET AAN

De fprintf, printf, sprintf, vprintf, vfprintf, en vsprintf functies voldoen aan de ANSI X3.159-1989 (’’ANSI C’’) en ISO/IEC 9899:1999 (’’ISO C99’’) standaarden. De snprintf en vsnprintf functies voldoen aan ISO/IEC 9899:1999.

Wat betreft de teruggeef waarde van snprintf spreken SUSv9 en C99 elkaar tegen: als snprintf aangeroepen wordt met size=0 dan schrijft SUSv2 een ongespecificeerde teruggeef waarde kleiner dan 1 voor, terwijl C99 in dit geval toestaat dat str NULL is; C99 schrijft als teruggeef waarde voor (net als altijd) het aantal karakters dat geschreven zou zijn als de uitvoer string groot genoeg zou zijn geweest.

Linux libc4 kent de vijf standaard C vlaggen. Het kent de lengte aanpassers h,l,L en de conversies cdeEfFgGinopsuxX, waar F een synoniem voor f is. Verder worden D,O,U als synoniemen voor ld,lo,lu geaccepteerd. (Dit is een kwalijke zaak, en veroorzaakte later ernstige bugs, toen %D niet meer ondersteund werd.) Geen localiteit-afhankelijk radix karakter, geen duizendtallen scheider, geen NaN of oneindig, geen %m$ en *m$.

Linux libc5 kent de vijf standaard C vlaggen, en de ’ vlag, localiteit, %m$ en *m$. Het kent de lengte aanpassers h,l,L,Z,q, maar accepteert L en q zowel voor long doubles als voor long integers (dit is een bug). De conversie karakters FDOU worden niet langer herkent, maar een nieuw conversie karakter m, dat strerror(errno) geeft, is toegevoegd.

glibc 2.0 voegt conversie karakters C en S toe.

glibc 2.1 voegt lengte aanpassers hh,j,t,z en conversie karakters a,A toe.

glibc 2.2 voegt het conversie karakter F met C99 semantiek, en het vlag karakter I toe.

GESCHIEDENIS

Unix V7 definieert de drie routines printf, fprintf, sprintf, en heeft de vlag -, de breedte of precisie *, de lengte aanpasser l, de conversies doxfegcsu, en D,O,U,X als synoniemen voor ld,lo,lu,lx. Dit geld ook nog voor BSD 2.9.1, maar BSD 2.10 heeft de vlaggen #, + en <spatie>; D,O,U,X worden niet meer genoemd. BSD 2.11 heeft vprintf, vfprintf, vsprintf, en waarschuwt D,O,U,X niet meer te gebruiken. BSD 4.3 Reno heeft de vlag 0, de lengte aanpassers h en L, en de conversies n, p, E, G, X (met huidige betekenis) en verklaart D,O,U als verouderd. BSD 4.4 indtroduceert de functies snprintf en vsnprintf, en de lengte aanpasser q. FreeBSD heeft ook de functies asprintf en vasprintf, die een buffer die groot genoeg is voor sprintf alloceren.

BUGS

Omdat sprintf en vsprintf uitgaan van een willekeurig lange string, moeten aanroepers oppassen dat ze niet over de aanwezige ruimte heengaan (overflow); het is vaak onmogelijk dit te verzekeren. Merk op dat de lengte van de geproduceerde strings locale-afhankelijk en moelijk te voorspellen is. Gebruik, in plaats hiervan, snprintf en vsnprintf (of asprintf en vasprintf).

Linux libc4.[45] heeft geen snprintf, maar levert een libbsd die een snprintf equivalent aan sprintf bevat, i.e., één die het size argument negeert. Daarom leidt het gebruik van snprintf met vroege libc4 tot ernstige beveiligingsproblemen.

Code zoals printf(foo); doet vaak een bug vermoeden, omdat foo een % karakter zou kunnen bevatten. Als foo van niet betrouwbare gebruikersinvoer komt, dan zou het een %n kunnen bevatten, wat de printf naar het geheugen doet schrijven en hiermee een beveiligingslek creëert.

Sommige floating point conversies onder vroege libc4 veroorzaakten lekken in het geheugen.

COMMENTS