Manipulace s řetězcem C - C string handling
| Standardní knihovna C. |
|---|
| Obecná témata |
| Různé záhlaví |
C programovací jazyk má sadu funkcí, provádějících operace řetězce (řetězce znaků a bajtů řetězce) ve své standardní knihovny . Jsou podporovány různé operace, jako je kopírování, zřetězení , tokenizace a vyhledávání. Pro znakových řetězců, standardní knihovna používá konvence, že řetězce jsou null zakončený : řetězec n znaků je reprezentován jako pole o n + 1 prvků, z nichž poslední je NULznak (s číselnou hodnotu 0).
Jedinou podporou řetězců ve správném programovacím jazyce je, že kompilátor překládá citované řetězcové konstanty do řetězců zakončených hodnotou null.
Definice
Řetězec je definován jako souvislá posloupnost kódových jednotek ukončená první jednotkou nulového kódu (často se nazývá jednotka kódu NUL ). To znamená, že řetězec nemůže obsahovat jednotku nulového kódu, protože první viděný označuje konec řetězce. Délka z řetězce je počet jednotek kódu před zero kódu jednotce. Paměť obsazená řetězcem je vždy o jednu jednotku kódu větší než délka, protože k uložení nulového terminátoru je potřeba místo.
Obecně termín řetězec znamená řetězec, kde kódová jednotka je typu char, což je přesně 8 bitů na všech moderních počítačích. C90 definuje široké řetězce, které používají kódovou jednotku typu wchar_t, což je 16 nebo 32 bitů na moderních strojích. To bylo určeno pro Unicode, ale stále častěji se místo toho používá UTF-8 v normálních řetězcích pro Unicode.
Řetězce jsou předávány do funkcí předáním ukazatele první jednotce kódu. Protože char*a wchar_t*jsou různé typy, funkce, které zpracovávají široké řetězce, se liší od těch, které zpracovávají normální řetězce, a mají různá jména.
Řetězcové literály ( "text"ve zdrojovém kódu C) jsou během kompilace převedeny na pole. Výsledkem je pole kódových jednotek obsahující všechny znaky plus koncová nulová kódová jednotka. V C90 L"text"produkuje široký řetězec. Řetězcový literál může obsahovat jednotku nulového kódu (jedním ze způsobů je vložit \0do zdroje), ale to způsobí, že řetězec v tomto bodě skončí. Zbytek literálu bude umístěn do paměti (s další nulovou kódovou jednotkou přidanou na konec), ale není možné vědět, že tyto kódové jednotky byly přeloženy z řetězcového literálu, proto takový zdrojový kód není řetězcový literál.
Kódování znaků
Každý řetězec končí při prvním výskytu jednotky nulového kódu příslušného druhu ( charnebo wchar_t). V důsledku toho může bajtový řetězec ( char*) obsahovat znaky jiné než NUL v ASCII nebo v libovolné příponě ASCII , ale nikoli znaky v kódováních, jako je UTF-16 (přestože 16bitová jednotka kódu může být nenulová, její vysoký nebo nízký bajt může být nula). Kódování, která lze uložit do širokých řetězců, jsou definována šířkou wchar_t. Ve většině implementací wchar_tje alespoň 16 bitů, a tak lze uložit všechna 16bitová kódování, jako je UCS-2 . Pokud wchar_tje 32bitové , lze uložit 32bitové kódování, například UTF-32 . (Standard vyžaduje „typ s libovolným širokým znakem“, který v systému Windows již neplatí od posunu UCS-2 na UTF-16.) C ++ 11 a C11 přidávají dva typy s explicitními šířkami char16_ta char32_t.
Kódování s proměnnou šířkou lze použít jak v bajtových řetězcích, tak v širokých řetězcích. Délka řetězce a offsety se měří v bytech nebo wchar_tnikoli ve "znacích", což může být pro začínající programátory matoucí. UTF-8 a Shift JIS se často používají v řetězcích C byte, zatímco UTF-16 se často používá v řetězcích C wide, když wchar_tje to 16 bitů. Zkrácení řetězců pomocí znaků s proměnnou délkou pomocí funkcí, jako jsou funkce, strncpymůže způsobit neplatné sekvence na konci řetězce. To může být nebezpečné, pokud jsou zkrácené části interpretovány kódem, který předpokládá, že je vstup platný.
Podpora literálů Unicode, jako jsou char foo[512] = "φωωβαρ";(UTF-8) nebo wchar_t foo[512] = L"φωωβαρ";(UTF-16 nebo UTF-32, závisí na wchar_t), je definována implementací a může vyžadovat, aby byl zdrojový kód ve stejném kódování, zejména charpokud kompilátory mohou kopírovat cokoli, co je mezi uvozovkami. Některé kompilátory nebo editory budou vyžadovat zadání všech znaků jiných než ASCII jako \xNNsekvencí pro každý bajt UTF-8 a/nebo \uNNNNpro každé slovo UTF-16. Od C11 (a C ++ 11) char foo[512] = u8"φωωβαρ";je k dispozici nová doslovná syntaxe, která zaručuje UTF-8 pro bytestring literál.
Přehled funkcí
Většina funkcí, které fungují na řetězcích C, je deklarována v string.hzáhlaví ( cstringv C ++), zatímco funkce, které fungují na C širokých řetězcích, jsou deklarovány v wchar.hzáhlaví ( cwcharv C ++). Tato záhlaví také obsahují deklarace funkcí používaných pro zpracování vyrovnávacích pamětí paměti; název je tedy něco jako nesprávné pojmenování.
Funkce deklarované v string.hjsou extrémně populární, protože jako součást standardní knihovny C zaručeně fungují na jakékoli platformě, která podporuje C. S těmito funkcemi však existují určité problémy se zabezpečením, například potenciální přetečení vyrovnávací paměti, pokud není používáno opatrně a správně , což přimělo programátory upřednostňovat bezpečnější a možná méně přenosné varianty, z nichž některé populární jsou uvedeny níže. Některé z těchto funkcí také porušují správnost konstitu tím, že přijmou constukazatel řetězce a vrátí v constukazateli řetězec bez ukazatele. Chcete -li to opravit, některé byly rozděleny do dvou přetížených funkcí ve verzi C ++ standardní knihovny.
V historické dokumentaci byl místo „bajtu“ pro řetězce C často používán výraz „znak“, což mnohé vede k domněnce, že tyto funkce pro UTF-8 nějak nefungují . Ve skutečnosti jsou všechny délky definovány jako v bajtech a to platí pro všechny implementace a tyto funkce fungují také s UTF-8 i s jednobajtovým kódováním. Dokumentace BSD byla opravena, aby to bylo jasné, ale dokumentace POSIX, Linux a Windows stále používá „znak“ na mnoha místech, kde je „byte“ nebo „wchar_t“ správný termín.
Funkce pro zpracování vyrovnávacích pamětí mohou zpracovávat sekvence bajtů, které jako součást dat obsahují null-byte. Názvy těchto funkcí obvykle začínají memopačně než strpředpona.
Konstanty a typy
| název | Poznámky |
|---|---|
NULL |
Makro expandující na konstantu nulového ukazatele ; tj. konstanta představující hodnotu ukazatele, která zaručeně není platnou adresou objektu v paměti. |
wchar_t
|
Typ používaný pro kódovou jednotku v širokých řetězcích, obvykle 16bitové nebo 32bitové hodnoty bez znaménka. Pro tyto kódové jednotky není specifikována žádná konkrétní interpretace; standard C vyžaduje pouze to, aby wchar_t byl dostatečně široký, aby pojal nejširší znakovou sadu mezi podporovanými místními systémy . Teoreticky může mít wchar_t stejnou velikost jako char , a proto není schopen pojmout kódové jednotky UTF-32 nebo UTF-16 . |
wint_t
|
Celočíselný typ, který může obsahovat libovolnou hodnotu wchar_t i hodnotu makra WEOF. Tento typ se nezměnil integrovanými akcemi. Obvykle 32bitová podepsaná hodnota. |
mbstate_t
|
Obsahuje všechny informace o stavu převodu požadované od jednoho volání funkce k druhému. |
Funkce
| Bajtový řetězec |
Široký provázek |
Popis | |
|---|---|---|---|
| řetězec manipulace |
strcpy
|
wcscpy
|
Zkopíruje jeden řetězec do druhého |
strncpy
|
wcsncpy
|
Zapisuje přesně n bytů, kopíruje ze zdroje nebo přidává hodnoty null | |
strcat
|
wcscat
|
Připojí jeden řetězec k druhému | |
strncat
|
wcsncat
|
Připojí ne více než n bajtů z jednoho řetězce do druhého | |
strxfrm
|
wcsxfrm
|
Transformuje řetězec podle aktuálního národního prostředí | |
| Smyčcové vyšetření |
strlen
|
wcslen
|
Vrátí délku řetězce |
strcmp
|
wcscmp
|
Porovná dva řetězce ( třícestné srovnání ) | |
strncmp
|
wcsncmp
|
Porovná konkrétní počet bajtů ve dvou řetězcích | |
strcoll
|
wcscoll
|
Porovná dva řetězce podle aktuálního národního prostředí | |
strchr
|
wcschr
|
Vyhledá první výskyt bajtu v řetězci | |
strrchr
|
wcsrchr
|
Vyhledá poslední výskyt bajtu v řetězci | |
strspn
|
wcsspn
|
Vrátí počet počátečních bajtů v řetězci, které jsou ve druhém řetězci | |
strcspn
|
wcscspn
|
Vrátí počet počátečních bajtů v řetězci, které nejsou ve druhém řetězci | |
strpbrk
|
wcspbrk
|
Vyhledá v řetězci první výskyt bajtu v sadě | |
strstr
|
wcsstr
|
Vyhledá první výskyt podřetězce v řetězci | |
strtok
|
wcstok
|
Rozdělí řetězec na tokeny | |
| Smíšený |
strerror
|
N/A | Vrátí řetězec obsahující zprávu odvozenou z kódu chyby |
Manipulace s pamětí |
memset
|
wmemset
|
Vyplní vyrovnávací paměť opakovaným bajtem |
memcpy
|
wmemcpy
|
Zkopíruje jednu vyrovnávací paměť do druhé | |
memmove
|
wmemmove
|
Zkopíruje jednu vyrovnávací paměť do druhé, případně překrývající se vyrovnávací paměti | |
memcmp
|
wmemcmp
|
Porovná dvě vyrovnávací paměti (třícestné srovnání) | |
memchr
|
wmemchr
|
Vyhledá první výskyt bajtu ve vyrovnávací paměti | |
|
|||
Vícebajtové funkce
| název | Popis |
|---|---|
mblen
|
Vrátí počet bajtů v dalším vícebajtovém znaku |
mbtowc
|
Převede další vícebajtový znak na široký znak |
wctomb
|
Převede široký znak na vícebajtovou reprezentaci |
mbstowcs
|
Převede vícebajtový řetězec na široký řetězec |
wcstombs
|
Převede široký řetězec na vícebajtový řetězec |
btowc
|
Pokud je to možné, převeďte jednobajtový znak na široký |
wctob
|
Pokud je to možné, převeďte široký znak na jednobajtový znak |
mbsinit
|
Zkontroluje, zda objekt stavu představuje počáteční stav |
mbrlen
|
Vrátí počet bajtů v dalším vícebajtovém znaku v daném stavu |
mbrtowc
|
Převede další vícebajtový znak na široký znak v daném stavu |
wcrtomb
|
Převede široký znak na vícebajtovou reprezentaci v daném stavu |
mbsrtowcs
|
Převede vícebajtový řetězec na široký řetězec v daném stavu |
wcsrtombs
|
Převede široký řetězec na vícebajtový řetězec v daném stavu |
Všechny tyto funkce mají ukazatel na a mbstate_tobjekt, který musí volající udržovat. Toto bylo původně určeno ke sledování stavů posunu vmbkódování, ale moderní, jako je UTF-8, to nepotřebují. Tyto funkce však byly navrženy za předpokladu, žetoaletakódování není kódování s proměnnou šířkou, a proto jsou navrženy tak, aby se zabývaly přesně jednímwchar_tnajednou předávání podle hodnoty, nikoli pomocí řetězcového ukazatele. Protože UTF-16 je kódování s proměnnou šířkou,mbstate_t byl znovu použit ke sledování náhradních párů v širokém kódování, ačkoli volající stále musí detekovat a volat mbtowc dvakrát pro jednu postavu.
Číselné převody
| Bajtový řetězec |
Široký provázek |
Popis |
|---|---|---|
atof
|
N/A | převede řetězec na hodnotu s plovoucí desetinnou čárkou ('atof' znamená 'ASCII to float') |
atoiatolatoll
|
N/A | převede řetězec na celé číslo ( C99 ) ('atoi' znamená 'ASCII na celé číslo') |
strtof( C99 ) strtodstrtold( C99 )
|
wcstof( C99 ) wcstodwcstold( C99 )
|
převede řetězec na hodnotu s plovoucí desetinnou čárkou |
strtolstrtoll
|
wcstolwcstoll
|
převede řetězec na celé číslo se znaménkem |
strtoulstrtoull
|
wcstoulwcstoull
|
převede řetězec na celé číslo bez znaménka |
|
||
Standardní knihovna C obsahuje několik funkcí pro číselné převody. Funkce, které se zabývají řetězci bajtů, jsou definovány v stdlib.hzáhlaví ( cstdlibhlavička v C ++). Funkce, které se zabývají širokými řetězci, jsou definovány v wchar.hzáhlaví ( cwcharhlavička v C ++).
Tyto strtoxxxfunkce nejsou const korektní , protože přijmout constukazatel řetězce a vrátí bez možnosti constukazatel v rámci řetězce.
Také od normativního dodatku 1 (C95) atoxxjsou funkce považovány za zahrnuté do strtoxxxfunkcí, a proto ani C95, ani žádný pozdější standard neposkytuje rozsáhlé verze těchto funkcí. Argumentem proti atoxxje, že nerozlišují mezi chybou a 0.
Oblíbená rozšíření
| název | Plošina | Popis |
|---|---|---|
bzero
|
POSIX , BSD | Vyplní vyrovnávací paměť nulovými bajty, zastaralá o memset
|
memccpy
|
SVID , POSIX | zkopíruje až na zadaný počet bajtů mezi dvě paměťové oblasti, které se nesmí překrývat, a zastaví se, když je nalezen daný bajt. |
mempcpy
|
GNU | varianta memcpyvrácení ukazatele na bajt následující za posledním zapsaným bajtem
|
strcasecmp
|
POSIX, BSD | verze bez rozlišení velkých a malých písmen strcmp
|
strcat_s
|
Okna | varianta, strcatkterá před kopírováním zkontroluje velikost cílové vyrovnávací paměti
|
strcpy_s
|
Okna | varianta, strcpykterá před kopírováním zkontroluje velikost cílové vyrovnávací paměti
|
strdup
|
POSIX | přiděluje a duplikuje řetězec |
strerror_r
|
POSIX 1, GNU | jeho varianta strerrorje bezpečná pro vlákna. Verze GNU není kompatibilní s verzí POSIX.
|
stricmp
|
Okna | verze bez rozlišení velkých a malých písmen strcmp
|
strlcpy
|
BSD, Solaris | varianta, strcpykterá zkrátí výsledek, aby se vešel do cílového bufferu
|
strlcat
|
BSD, Solaris | varianta, strcatkterá zkrátí výsledek, aby se vešel do cílového bufferu
|
strsignal
|
POSIX: 2008 | vrací řetězcovou reprezentaci signálního kódu . Není bezpečné vlákno. |
strtok_r
|
POSIX | jeho varianta strtokje bezpečná pro vlákna
|
Náhrady
Přes dobře zavedené potřebě nahradit strcata strcpyfunkcemi, které neumožňují přetečení zásobníku, žádný uznávaný standard vznikl. Toto je částečně kvůli mylné víře, u mnoha C programátorů, že strncata strncpymají požadované chování; k tomu však nebyla navržena ani jedna funkce (byly určeny k manipulaci s vyrovnávací pamětí řetězců pevné velikosti s nulovým polstrováním, datovým formátem, který se v moderním softwaru běžně nepoužívá), a chování a argumenty jsou neintuitivní a často i nesprávně napsané odborníkem programátoři.
Nejoblíbenější náhradou jsou funkce strlcata strlcpy, které se objevily v OpenBSD 2.4 v prosinci 1998. Tyto funkce vždy zapíší jednu NUL do cílového bufferu, v případě potřeby zkrátí výsledek a vrátí velikost bufferu, který by byl potřeba, což umožňuje detekci zkrácení a poskytuje velikost pro vytvoření nové vyrovnávací paměti, která nebude zkrácena. Byly kritizovány na základě údajné neefektivity, podpory používání řetězců C (namísto nějaké lepší alternativní formy řetězce) a skrývání dalších potenciálních chyb. V důsledku toho nebyly zahrnuty do knihovny GNU C (používané softwarem v Linuxu), přestože jsou implementovány v knihovnách C pro OpenBSD, FreeBSD , NetBSD , Solaris , OS X a QNX , stejně jako v alternativních C knihovnách pro Linux, například musl představený v roce 2011. Nedostatek podpory knihovny GNU C nezastavil různé autory softwaru v jeho používání a sdružování náhrady, mimo jiné SDL , GLib , ffmpeg , rsync , a dokonce i interně v linuxovém jádře . K dispozici jsou implementace open source pro tyto funkce.
Někdy memcpynebo memmovese používají, protože mohou být efektivnější, než strcpykdyž opakovaně nekontrolují NUL (u moderních procesorů to platí méně). Protože jako parametr potřebují délku vyrovnávací paměti, správné nastavení tohoto parametru může zabránit přetečení vyrovnávací paměti.
V rámci svého životního cyklu rozvoje zabezpečení z roku 2004 společnost Microsoft představila řadu „zabezpečených“ funkcí včetně strcpy_sa strcat_s(spolu s mnoha dalšími). Tyto funkce byly standardizovány s několika drobnými změnami jako součást volitelné C11 (příloha K) navržené ISO/IEC WDTR 24731. Tyto funkce provádějí různé kontroly, včetně toho, zda řetězec není příliš dlouhý, aby se vešel do vyrovnávací paměti. Pokud kontroly selžou, je volána uživatelem specifikovaná funkce „handler-constraint handler“, která program obvykle přeruší. Některé funkce provádějí destruktivní operace před voláním obslužné rutiny omezení běhu; například strcat_snastaví cíl na prázdný řetězec, což může ztížit zotavení z chybových stavů nebo jejich ladění. Tyto funkce přitahovaly značnou kritiku, protože zpočátku byly implementovány pouze ve Windows a současně Microsoft Visual C ++ začal vytvářet varovné zprávy, které navrhovaly programátorům používat tyto funkce místo standardních. Někteří to spekulovali jako o pokusu Microsoftu zamknout vývojáře na jeho platformě. Ačkoli jsou k dispozici open-source implementace těchto funkcí, tyto funkce nejsou v běžných unixových knihovnách C k dispozici. Zkušenosti s těmito funkcemi ukázaly značné problémy s jejich přijetím a chyby v používání, proto je pro příští revizi normy C navrženo odstranění přílohy K. Využití memset_sBylo také navrženo jako způsob, aby se zabránilo nežádoucím optimalizace kompilátoru.
Viz také
- Syntaxe C § Řetězce - syntaxe zdrojového kódu včetně únikových sekvencí zpětného lomítka
- Řetězcové funkce
Poznámky
Reference
externí odkazy
- Rychlé memcpy v C , více příkladů kódování C pro cílení na různé typy architektur instrukcí CPU