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 NUL
znak (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 \0
do 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 ( char
nebo 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_t
je alespoň 16 bitů, a tak lze uložit všechna 16bitová kódování, jako je UCS-2 . Pokud wchar_t
je 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_t
a 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_t
nikoli 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_t
je to 16 bitů. Zkrácení řetězců pomocí znaků s proměnnou délkou pomocí funkcí, jako jsou funkce, strncpy
můž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 char
pokud 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 \xNN
sekvencí pro každý bajt UTF-8 a/nebo \uNNNN
pro 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.h
záhlaví ( cstring
v C ++), zatímco funkce, které fungují na C širokých řetězcích, jsou deklarovány v wchar.h
záhlaví ( cwchar
v 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.h
jsou 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 const
ukazatel řetězce a vrátí v const
ukazateli ř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í mem
opačně než str
př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') |
atoi atol atoll
|
N/A | převede řetězec na celé číslo ( C99 ) ('atoi' znamená 'ASCII na celé číslo') |
strtof ( C99 ) strtod strtold ( C99 )
|
wcstof ( C99 ) wcstod wcstold ( C99 )
|
převede řetězec na hodnotu s plovoucí desetinnou čárkou |
strtol strtoll
|
wcstol wcstoll
|
převede řetězec na celé číslo se znaménkem |
strtoul strtoull
|
wcstoul wcstoull
|
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.h
záhlaví ( cstdlib
hlavička v C ++). Funkce, které se zabývají širokými řetězci, jsou definovány v wchar.h
záhlaví ( cwchar
hlavička v C ++).
Tyto strtoxxx
funkce nejsou const korektní , protože přijmout const
ukazatel řetězce a vrátí bez možnosti const
ukazatel v rámci řetězce.
Také od normativního dodatku 1 (C95) atoxx
jsou funkce považovány za zahrnuté do strtoxxx
funkcí, a proto ani C95, ani žádný pozdější standard neposkytuje rozsáhlé verze těchto funkcí. Argumentem proti atoxx
je, ž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 memcpy vrá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, strcat která před kopírováním zkontroluje velikost cílové vyrovnávací paměti
|
strcpy_s
|
Okna | varianta, strcpy která 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 strerror je 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, strcpy která zkrátí výsledek, aby se vešel do cílového bufferu
|
strlcat
|
BSD, Solaris | varianta, strcat která 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 strtok je bezpečná pro vlákna
|
Náhrady
Přes dobře zavedené potřebě nahradit strcat
a strcpy
funkcemi, 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 strncat
a strncpy
mají 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 strlcat
a 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 memcpy
nebo memmove
se používají, protože mohou být efektivnější, než strcpy
když 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_s
a 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_s
nastaví 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_s
Bylo 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