řetězec formátu printf - printf format string
řetězec formátu printf odkazuje na kontrolní parametr používaný třídou funkcí ve vstupních / výstupních knihovnách jazyka C a mnoha dalších programovacích jazyků . Řetězec je napsán v jednoduchém jazyce šablony : znaky se obvykle kopírují doslova do výstupu funkce, ale specifikátory formátu , které začínají %
znakem, označují umístění a způsob převodu části dat (například čísla) na znaky.
„printf“ je název jedné z hlavních výstupních funkcí jazyka C a znamená „ print f ormatted“. řetězce formátu printf doplňují řetězce formátu scanf , které poskytují formátovaný vstup ( syntaktickou analýzu ). V obou případech poskytují jednoduchou funkčnost a pevný formát ve srovnání se sofistikovanějšími a flexibilnějšími šablonami nebo analyzátory, ale jsou dostatečné pro mnoho účelů.
Mnoho jazyků jiných než C kopíruje syntaxi řetězce printf formátu přesně nebo přesně ve svých vlastních I / O funkcích.
Neshody mezi specifikátory formátu a typem dat mohou způsobit selhání a další chyby zabezpečení. Samotný formátovací řetězec je velmi často řetězcový literál , který umožňuje statickou analýzu volání funkce. Může to však být také hodnota proměnné, která umožňuje dynamické formátování, ale také chybu zabezpečení známou jako zneužití nekontrolovaného řetězce formátu .
Dějiny
Rané programovací jazyky, jako je Fortran, používaly k vytváření popisů formátování speciální příkazy se zcela odlišnou syntaxí od jiných výpočtů. V tomto příkladu je formát uveden na řádku 601 a příkaz WRITE na něj odkazuje číslem řádku:
WRITE OUTPUT TAPE 6, 601, IA, IB, IC, AREA 601 FORMAT (4H A= ,I5,5H B= ,I5,5H C= ,I5, & 8H AREA= ,F10.2, 13H SQUARE UNITS)
ALGOL 68 měl více funkčních API , ale stále používal speciální syntaxi ( $
oddělovače obklopují speciální syntaxi formátování):
printf(($"Color "g", number1 "6d,", number2 "4zd,", hex "16r2d,", float "-d.2d,", unsigned value"-3d"."l$,
"red", 123456, 89, BIN 255, 3.14, 250));
Ale použití volání normální funkce a datových typů zjednodušuje jazyk a kompilátor a umožňuje, aby implementace vstupu / výstupu byla zapsána ve stejném jazyce. Tyto výhody převažují nad nevýhodami (jako je naprostý nedostatek bezpečnosti typu v mnoha případech) a ve většině novějších jazyků není I / O součástí syntaxe.
C se printf
má svůj původ v BCPL ‚s writef
funkcí (1966). Ve srovnání s C
a printf
, *N
je úniková sekvence jazyka BCPL představující znak nového řádku (pro který C používá únikovou sekvenci \n
) a pořadí šířky a typu pole specifikace formátu je obráceno v writef
:
WRITEF("%I2-QUEENS PROBLEM HAS %I5 SOLUTIONS*N", NUMQUEENS, COUNT)
Pravděpodobně první kopírování syntaxe mimo jazyk C byl příkaz Unix printf
shell, který se poprvé objevil ve verzi 4 , jako součást portu do C.
Specifikace zástupného formátu
Formátování probíhá prostřednictvím zástupných symbolů v řetězci formátu. Pokud by například program chtěl vytisknout věk osoby, mohl by výstup představit předponou „Váš věk je“ a pomocí podepsaného znaku desítkového specifikátoru d
označit, že chceme, aby se celé číslo pro věk zobrazilo okamžitě po této zprávě můžeme použít formátovací řetězec:
printf("Your age is %d", age);
Syntax
Syntaxe zástupného symbolu formátu je
% [ parametr ] [ příznaky ] [ šířka ] [. přesnost ] [ délka ] typ
Pole parametru
Toto je rozšíření POSIX a ne v C99 . Pole Parametr lze vynechat nebo může být:
Charakter Popis n $ n je číslo parametru, který se má zobrazit pomocí tohoto specifikátoru formátu, což umožňuje výstup poskytovaných parametrů vícekrát, s použitím různých specifikátorů formátu nebo v různých objednávkách. Pokud některý jediný zástupný symbol určuje parametr, MUSÍ také určit všechny ostatní zástupné symboly.
Napříkladprintf("%2$d %2$#x; %1$d %1$#x",16,17)
produkuje17 0x11; 16 0x10
.
Tato vlastnost vidí hlavně jeho použití v lokalizaci, kde se pořadí výskytu parametrů liší kvůli jazykově závislé konvenci.
V systému Microsoft Windows, který není POSIX, je podpora této funkce umístěna do samostatné funkce printf_p.
Pole příznaků
Pole Příznaky může být nula nebo více (v libovolném pořadí) z:
Charakter Popis -
(minus)Zarovnejte výstup tohoto zástupného symbolu doleva. (Výchozí nastavení je zarovnání výstupu doprava.) +
(plus)Prepends plus pro kladné znaménko-číselné typy. pozitivní = + , negativní = - .
(Výchozí hodnota nic před kladnými čísly nepřepíše.)
(prostor)Prepends prostor pro kladné znaménko-číselné typy. pozitivní =
(Výchozí hodnota nic před kladnými čísly nepřepíše.)0
(nula)Když je zadána možnost 'šířka', předloží nula pro číselné typy. (Výchozí předřazuje mezery.)
Napříkladprintf("%4X",3)
produkuje3
, zatímcoprintf("%04X",3)
produkuje0003
.'
(apostrof)Celé číslo nebo exponent desetinného místa má použit oddělovač seskupení tisíců. #
(hash)Alternativní forma:
U typů g a G nejsou odstraněny koncové nuly.
U typů f , F , e , E , g , G výstup vždy obsahuje desetinnou čárku.
U typů o , x , X je text 0 , 0x , 0X předřazen nenulovým číslům.
Šířkové pole
Pole Šířka určuje minimální počet znaků pro výstup a obvykle se používá k vyplnění polí s pevnou šířkou v tabulkovém výstupu, kde by pole byla jinak menší, i když nezpůsobí zkrácení nadměrných polí.
Pole šířky může být vynecháno, nebo číselná celočíselná hodnota nebo dynamická hodnota, když je předána jako další argument, když je označena hvězdičkou * . printf("%*d", 5, 10)
Výsledkem bude například 10
tisk s celkovou šířkou 5 znaků.
Ačkoli není součástí pole šířky, úvodní nula je interpretována jako příznak nulového výplně uvedený výše a se zápornou hodnotou se zachází jako s kladnou hodnotou ve spojení s příznakem zarovnání doleva - také zmíněným výše.
Přesné pole
Pole Přesnost obvykle určuje maximální limit výstupu v závislosti na konkrétním typu formátování. U číselných typů s plovoucí desetinnou čárkou určuje počet číslic napravo od desetinné čárky, které mají být zaokrouhleny. U typu řetězce omezuje počet znaků, které by měly být na výstupu, po kterém je řetězec zkrácen.
Pole přesnosti může být vynecháno, nebo číselná celočíselná hodnota nebo dynamická hodnota, když je předána jako další argument, když je označena hvězdičkou * . Například printf("%.*s", 3, "abcdef")
bude mít za následek abc
tisk.
Pole délky
Pole Délka lze vynechat nebo být libovolné z:
Charakter Popis hh U celočíselných typů způsobí printf očekávání celočíselného argumentu velikosti int, který byl povýšen z char . h Pro typy celočíselných způsobuje printf očekávat int -sized argument celého čísla, která byla podporována ze zkratu . l Pro celočíselné typy způsobí, že printf očekává celočíselný argument dlouhé velikosti. U typů s plovoucí desetinnou čárkou je toto ignorováno. float argumenty jsou vždy povýšeny na dvojnásobek, pokud jsou použity ve volání varargs.
ll U celočíselných typů způsobí, že printf očekává dlouhý celočíselný argument dlouhé . L U typů s plovoucí desetinnou čárkou způsobí, že printf očekává dlouhý dvojitý argument. z U celočíselných typů způsobí, že printf očekává celočíselný argument size_t -ized. j U celočíselných typů způsobí, že printf očekává celočíselný argument intmax_t -ized. t U celočíselných typů způsobí, že printf očekává celočíselný argument ptrdiff_t - velikost.
Před rozšířeným používáním rozšíření ISO C99 navíc existovalo několik možností délky pro konkrétní platformu:
Postavy Popis Já U podepsaných celočíselných typů způsobí printf očekávání ptrdiff_t -sized integer argument; pro nepodepsané celočíselné typy způsobí, že printf bude očekávat argument size_t -sized integer argument. Běžně se vyskytuje na platformách Win32 / Win64. I32 U celočíselných typů způsobí, že printf očekává 32bitový (dvojslovný) celočíselný argument. Běžně se vyskytuje na platformách Win32 / Win64. I64 U celočíselných typů způsobí, že printf očekává 64bitový (čtyřslovný) celočíselný argument. Běžně se vyskytuje na platformách Win32 / Win64. q U celočíselných typů způsobí, že printf očekává 64bitový (čtyřslovný) celočíselný argument. Běžně se vyskytuje na platformách BSD.
ISO C99 obsahuje inttypes.h
soubor záhlaví, který obsahuje řadu maker pro použití v printf
kódování nezávislém na platformě . Musí to být mimo uvozovky, napřprintf("%" PRId64 "\n", t);
Mezi příklady maker patří:
Makro Popis PRId32 Obvykle ekvivalentní I32d ( Win32 / Win64 ) nebo d PRId64 Typicky ekvivalentní I64d ( Win32 / Win64 ), lld ( 32bitové platformy ) nebo ld ( 64bitové platformy ) PRIi32 Obvykle ekvivalentní I32i ( Win32 / Win64 ) nebo i PRIi64 Typicky ekvivalentní I64i ( Win32 / Win64 ), lli ( 32bitové platformy ) nebo li ( 64bitové platformy ) PRIu32 Typicky ekvivalentní I32u ( Win32 / Win64 ) nebo u PRIu64 Obvykle ekvivalentní I64u ( Win32 / Win64 ), llu ( 32bitové platformy ) nebo lu ( 64bitové platformy ) PRIx32 Obvykle ekvivalentní I32x ( Win32 / Win64 ) nebo x PRIx64 Obvykle ekvivalentní I64x ( Win32 / Win64 ), llx ( 32bitové platformy ) nebo lx ( 64bitové platformy )
Zadejte pole
Pole Typ může být kterékoli z:
Charakter Popis % Vytiskne doslovný znak % (tento typ nepřijímá žádné příznaky, pole šířky, přesnosti, délky). d , i int jako celé číslo se znaménkem . % d a % i jsou synonymem pro výstup, ale liší se při použití scanf
pro vstup (kde použití % i bude interpretovat číslo jako hexadecimální, pokud mu předchází 0x , a osmičkové, pokud mu předchází 0. )u Tisk desítkové nepodepsané int . f , F zdvojnásobit v normální ( fixní ) notaci. f a F se liší pouze v tom, jak jsou vytištěny řetězce pro nekonečné číslo nebo NaN ( inf , nekonečno a nan pro f ; INF , INFINITY a NAN pro F ). e , E dvojnásobná hodnota ve standardní formě ( d . ddd e ± dd ). E konverze používá dopis E (spíše než e ) zavést exponent. Exponent vždy obsahuje alespoň dvě číslice; pokud je hodnota nula, je exponent 00 . Ve Windows obsahuje exponent ve výchozím nastavení tři číslice, např. 1.5e002 , ale toto může být změněno _set_output_format
funkcí specifickou pro Microsoft .g , G zdvojnásobte buď normální nebo exponenciální notaci, podle toho, co je pro její velikost vhodnější. g používá malá písmena, G používá velká písmena. Tento typ se mírně liší od notace s pevnou čárkou v tom, že nejsou zahrnuty zanedbatelné nuly napravo od desetinné čárky. Desetinná čárka také není uvedena na celých číslech. x , X unsigned int jako šestnáctkové číslo. x používá malá písmena a X velká písmena. Ó unsigned int v osmičkovém formátu. s řetězec zakončený nulou . C char (znak). p void * (ukazatel na void) ve formátu definovaném implementací. a , A zdvojnásobte hexadecimální zápis, počínaje 0x nebo 0X . a používá malá písmena, A používá velká písmena. (C ++ 11 iostreams mají hexfloat, který funguje stejně). n Netiskněte nic, ale zapište počet dosud zapsaných znaků do parametru celočíselného ukazatele.
V Javě se vytiskne nový řádek.
Zástupné symboly vlastního formátu
Existuje několik implementací printf
podobných funkcí, které umožňují rozšíření mini jazyka založeného na únikových znacích , což umožňuje programátorovi mít specifickou funkci formátování pro nepředstavené typy. Jedním z nejznámějších je (nyní však) glibc ‚s . Je však zřídka používán kvůli skutečnosti, že je v konfliktu s kontrolou řetězce statického formátu. Dalším je vlastní formátovač Vstr , který umožňuje přidávat názvy víceznakových formátů.
register_printf_function()
Některé aplikace (například Apache HTTP Server ) obsahují své vlastní printf
funkce a vkládají do nich rozšíření. Všechny tyto problémy však mají stejné problémy register_printf_function()
.
Funkce jádra Linux printk
podporuje řadu způsobů, jak zobrazit struktury jádra pomocí generické %p
specifikace, připojením dalších znaků formátu. Například %pI4
vytiskne adresu IPv4 v desítkovém formátu s tečkami. To umožňuje kontrolu řetězce statického formátu ( %p
části) na úkor plné kompatibility s běžným printf.
Většina jazyků, které mají printf
funkci podobnou, obchází nedostatek této funkce pouhým použitím %s
formátu a převedením objektu na řetězcovou reprezentaci.
Zranitelnosti
Neplatné specifikace převodu
Pokud je poskytnuto příliš málo argumentů funkcí k zadání hodnot pro všechny specifikace převodu v řetězci šablony, nebo pokud argumenty nejsou správných typů, výsledky jsou nedefinované, může dojít k chybě. Implementace jsou nekonzistentní ohledně toho, zda syntaktické chyby v řetězci spotřebovávají argument a jaký typ argumentu konzumují. Přebytečné argumenty jsou ignorovány. V řadě případů vedlo nedefinované chování k chybám zabezpečení typu „ Formátovat útok řetězce “ . Ve většině C nebo C ++ konvence volání mohou být předány argumenty na zásobníku, což znamená, že v případě příliš malého počtu argumentů bude printf číst za konec aktuálního stackframe, což umožňuje útočníkovi číst zásobník.
Některé překladače, jako je GNU Compiler Collection , staticky zkontrolují formátovací řetězce funkcí podobných printf a upozorní na problémy (při použití příznaků -Wall
nebo -Wformat
). GCC také varuje před uživatelem definovanými funkcemi stylu printf, pokud __attribute__
je na funkci použit nestandardní „formát“ .
Šířka pole versus explicitní oddělovače v tabulkovém výstupu
Použití pouze šířky pole k zajištění tabelace, stejně jako u formátu jako %8d%8d%8d
pro tři celá čísla ve třech 8místných sloupcích, nezaručí, že bude zachováno oddělení polí, pokud se v datech vyskytne velké množství. Ztráta oddělení polí může snadno vést k poškození výstupu. V systémech, které podporují použití programů jako stavebních kamenů ve skriptech, mohou být taková poškozená data často předávána a poškozovat další zpracování, bez ohledu na to, zda původní programátor očekával, že výstup bude čten pouze lidskýma očima. Takové problémy lze odstranit zahrnutím explicitních oddělovačů, dokonce mezer, do všech tabulkových výstupních formátů. Jednoduše změna nebezpečného příkladu z dříve na to %7d %7d %7d
řeší toto, formátování identicky, dokud se čísla nezvětší, ale poté jim explicitně zabráníte ve sloučení na výstupu kvůli explicitně zahrnutým mezerám. Podobné strategie platí i pro řetězcová data.
Zápis do paměti
Ačkoli je výstupní funkcí na povrchu, printf
umožňuje zápis do paměťového umístění určeného argumentem prostřednictvím %n
. Tato funkce se příležitostně používá jako součást komplikovanějších formátovacích řetězcových útoků.
Díky této %n
funkci je Turingprintf
omylem kompletní i s dobře sestavenou sadou argumentů. Hra tic-tac-toe napsaná ve formátu řetězce je vítězem 27. IOCCC .
Programovací jazyky s printf
Jazyky, které používají formátovací řetězce, které se odchylují od stylu v tomto článku (například AMPL a Elixir ), jazyky, které dědí jejich implementaci z JVM nebo jiného prostředí (například Clojure a Scala ), a jazyky, které nemají standardní nativní tisk implementace, ale mají externí knihovny, které emulují chování tisku (například JavaScript ), nejsou v tomto seznamu zahrnuty.
- awk (přes sprintf)
- C
- D
- F#
- G ( LabVIEW )
- GNU MathProg
- GNU oktáva
- Jít
- Haskell
- J
- Jazyky Java (od verze 1.5) a JVM
- Julia (prostřednictvím standardní knihovny Printf; knihovna Formatting.jl přidává obecné formátování ve stylu Pythonu a „část tohoto balíčku ve stylu c si klade za cíl obejít omezení, které musí @sprintf převzít doslovným řetězcovým argumentem.“)
- Lua (string.format)
- Javor
- MATLAB
- Max (prostřednictvím objektu sprintf)
- Mythryl
- PARI / GP
- Perl
- PHP
-
Python (prostřednictvím
%
operátora) - R
-
Raku (přes
printf
,sprintf
afmt
) - Červená / systém
- Rubín
- Tcl (pomocí příkazu formátu)
- Transact-SQL (prostřednictvím xp_sprintf )
-
Vala (přes
print()
aFileStream.printf()
) - Příkaz
printf
obslužného programu, někdy zabudovaný do shellu, například u některých implementací KornShell (ksh), Bourne opět shell (bash) nebo Z shell (zsh). Tyto příkazy obvykle interpretují únik C ve formátu řetězce.
Viz také
- Formát (Common Lisp)
- C standardní knihovna
- Naformátujte útok řetězce
iostream
- ML (programovací jazyk)
- printf ladění
printf
(Unix)-
printk
(tisknout zprávy jádra) scanf
- interpolace řetězců
Reference
externí odkazy
- C ++ reference pro
std::fprintf
- Rychlá reference ke specifikacím formátu gcc printf
- The Single UNIX Specification , Issue 7 from The Open Group : print formatted output - System Interfaces Reference,
Formatter
Specifikace v jazyce Java 1.5printf(1)
Integrovaný GNU Bash