Únikové sekvence v C - Escape sequences in C

Únikové sekvence se používají v programovacích jazycích C a C ++ a jejich design byl zkopírován do mnoha dalších jazyků, jako je Java , PHP , C# atd. Úniková sekvence je posloupnost znaků, která se při použití uvnitř znaku nepředstavuje doslovný řetězec , ale je přeložen do jiného znaku nebo posloupnosti znaků, jejichž znázornění může být obtížné nebo nemožné přímo.

V C se všechny únikové sekvence skládají ze dvou nebo více znaků, z nichž první je zpětné lomítko, \ (nazývá se " znak úniku "); zbývající znaky určují interpretaci únikové sekvence. Například \ n je úniková sekvence, která označuje znak nového řádku .

Motivace

Předpokládejme, že chceme vytisknout Hello, na jednom řádku, následovaný světem! na dalším řádku. Jeden by se mohl pokusit reprezentovat řetězec, který má být vytištěn jako jeden literál, následujícím způsobem:

#include <stdio.h>
int main() {
    printf("Hello,
world!");
}

Toto není platné v jazyce C, protože řetězcový literál nesmí zahrnovat více logických zdrojových řádků. To lze vyřešit tiskem znaku nového řádku pomocí jeho číselné hodnoty ( 0x0A v ASCII ),

#include <stdio.h>
int main() {
    printf("Hello,%cworld!", 0x0A);
}

To dává programu pokyn vytisknout Hello, následovaný bajtem, jehož číselná hodnota je 0x0A , následovaný světem! . I když to bude skutečně fungovat, když stroj používá kódování ASCII, nebude to fungovat na systémech, které používají jiné kódování, které mají pro znak nového řádku jinou číselnou hodnotu. Není to také dobré řešení, protože stále neumožňuje reprezentovat znak nového řádku uvnitř literálu a místo toho využívá sémantiky printf . Aby bylo možné tyto problémy vyřešit a zajistit maximální přenositelnost mezi systémy, C interpretuje \ n uvnitř literálu jako znak nového řádku, ať už je v cílovém systému jakýkoli:

#include <stdio.h>
int main() {
    printf("Hello,\nworld!");
}

V tomto kódu úniková sekvence \ n nestojí za zpětným lomítkem následovaným písmenem n , protože zpětné lomítko způsobí „únik“ z normálního způsobu, jakým jsou znaky interpretovány překladačem. Poté, co kompilátor uvidí zpětné lomítko, očekává, že další znak dokončí únikovou sekvenci, a poté převede únikovou sekvenci do bajtů, které má reprezentovat. Proto: „Dobrý den, \ nworld!“ představuje řetězec s vloženým novým řádkem bez ohledu na to, zda je použit uvnitř printf nebo kdekoli jinde.

To vyvolává problém, jak reprezentovat skutečné zpětné lomítko uvnitř literálu. To se provádí pomocí únikové sekvence \\ , jak je vidět v další části.

Některé jazyky nemají únikové sekvence, například Pascal . Místo toho bude použit příkaz obsahující nový řádek (writeeln obsahuje nový řádek, zápis jej vyloučí).

writeln('Hello');
write('world!');

Tabulka únikových sekvencí

Následující únikové sekvence jsou definovány ve standardu C. Tato tabulka také ukazuje hodnoty, na které se mapují v ASCII. Tyto únikové sekvence však lze použít na jakémkoli systému s kompilátorem C a mohou mapovat na jiné hodnoty, pokud systém nepoužívá kódování znaků založené na ASCII.

Úniková sekvence Šestihranná hodnota v ASCII Postava zastoupena
\A 07 Alert (Beep, Bell) (přidáno v C89)
\ b 08 Backspace
\E 1B Úniková postava
\F 0C Přerušení stránky ve formátu Formfeed
\ n 0A Newline (Line Feed); viz poznámky níže
\ r 0D Návrat vozíku
\ t 09 Horizontální tab
\proti 0B Svislá tab
\\ 5C Obrácené lomítko
\ ' 27 Apostrof nebo jednoduchá uvozovka
\ " 22 Dvojité uvozovky
\? 3F Otazník (používá se k vyloučení trigrafů )
\ nnn žádný Bajt, jehož číselná hodnota je dána nnn, interpretován jako osmičkové číslo
\ x hh… žádný Bajt, jehož číselná hodnota je dána hh ... interpretován jako hexadecimální číslo
\ u hhhh žádný Kód Unicode ukazuje pod 10 000 hexadecimálních čísel (přidáno v C99)
\ U hhhhhhhh žádný Bod kódu Unicode, kde h je hexadecimální číslice
Poznámka 1. ^ Běžný nestandardní kód; viz část Poznámky níže.
Poznámka 2. ^ Může existovat jedna, dvě nebo tři osmičkové číslice n ; viz část Poznámky níže.
Poznámka 3. ^ \ u bere 4 hexadecimální číslice h ; viz část Poznámky níže.
Poznámka 4. ^ \ U má 8 hexadecimálních číslic h ; viz část Poznámky níže.

Poznámky

\ n produkuje jeden bajt, a to navzdory skutečnosti, že platforma může použít více než jeden bajt k označení nového řádku, jako je například sekvence DOS / Windows CR-LF, 0x0D 0x0A . K překladu z 0x0A do 0x0D 0x0A v systému DOS a Windows dochází, když je bajt zapsán do souboru nebo do konzoly, a inverzní překlad je proveden při čtení textových souborů.

Sekvence hexadecimálního úniku musí mít alespoň jednu hexadecimální číslici následující za \ x bez horní hranice; pokračuje tolika hexadecimálními číslicemi, kolik jich je. Například \ xABCDEFG označuje bajt s číselnou hodnotou ABCDEF 16 , za nímž následuje písmeno G , které není šestnáctkovou číslicí. Pokud je však výsledná celočíselná hodnota příliš velká na to, aby se vešla do jednoho bajtu, je skutečná přiřazená číselná hodnota definována implementací. Většina platforem má 8bitové typy znaků , které omezují užitečnou hexadecimální únikovou sekvenci na dvě hexadecimální číslice. Sekvence hexadecimálních sekvencí delší než dvě hexadecimální číslice však mohou být užitečné v rámci širokého znaku nebo širokého řetězcového literálu (s předponou L):

char s1[] = "\x12";       // single char with value 0x12 (18 in decimal)
char s1[] = "\x1234";     // single char with implementation-defined value, unless char is long enough
wchar_t s2[] = L"\x1234"; // single wchar_t with value 0x1234, provided wchar_t is long enough (16 bits suffices)

Osmičková úniková sekvence se skládá z \ následované jednou, dvěma nebo třemi osmičkovými číslicemi. Osmičková úniková sekvence končí, když buď již obsahuje tři osmičkové číslice, nebo další znak není osmičkovou číslicí. Například \ 11 je jedna osmičková úniková posloupnost označující bajt s číselnou hodnotou 9 (11 v osmičkové), nikoli úniková posloupnost \ 1 následovaná číslicí 1 . Nicméně, \ 1111 je osmičkové sekvence escape \ 111 následované číslicí 1 . Aby bylo možné označit bajt s číselnou hodnotou 1 následovanou číslicí 1 , lze použít "\ 1" "1" , protože C automaticky spojuje sousední řetězcové literály. Všimněte si toho, že některé tříciferné osmičkové únikové sekvence mohou být příliš velké, aby se vešly do jednoho bajtu; výsledkem je hodnota definovaná implementací pro skutečně vytvořený bajt. Úniková sekvence \ 0 je běžně používaná osmičková úniková sekvence, která označuje nulový znak s hodnotou nula.

Nestandardní únikové sekvence

Sekvence jako \ z není platnou únikovou sekvencí podle standardu C, protože se nenachází v tabulce výše. Standard C vyžaduje, aby byly diagnostikovány takové "neplatné" únikové sekvence (tj. Kompilátor musí vytisknout chybovou zprávu). Bez ohledu na tuto skutečnost mohou některé kompilátory definovat další únikové sekvence s implementací definovanou sémantikou. Příkladem je úniková sekvence \ e , která má v ASCII hexadecimální hodnotu 1B, představuje únikový znak a je podporována v GCC , clang a tcc . Nebyl však přidán do standardního repertoáru C, protože v některých znakových sadách (například EBCDIC ) nemá žádný smysluplný ekvivalent .

Univerzální jména postav

Od standardu C99 podporuje C také únikové sekvence, které označují body kódu Unicode v řetězcových literálech. Takové únikové sekvence se nazývají univerzální názvy znaků a mají tvar \ u hhhh nebo \ U hhhhhhhhh , kde h znamená hexadecimální číslici. Na rozdíl od ostatních uvažovaných únikových sekvencí se může univerzální název postavy rozšířit na více než jednu kódovou jednotku.

Sekvence \ u hhhh označuje bod kódu hhhh , interpretovaný jako hexadecimální číslo. Sekvence \ U hhhhhhhh označuje kódový bod hhhhhhhh , interpretovaný jako hexadecimální číslo. (Proto kódové body umístěné na U+10 000 nebo vyšší musí být označeny syntaxí \ U , zatímco nižší kódové body mohou používat \ u nebo \ U. ) Kódový bod je převeden na sekvenci kódových jednotek při kódování typ cíle v cílovém systému. Například (kde kódování je UTF-8 a UTF-16 pro wchar_t ):

char s1[] = "\xC0"; // A single byte with the value 0xC0, not valid UTF-8
char s2[] = "\u00C0"; // Two bytes with values 0xC3, 0x80, the UTF-8 encoding of U+00C0
wchar_t s3[] = L"\xC0"; // A single wchar_t with the value 0x00C0
wchar_t s4[] = L"\u00C0"; // A single wchar_t with the value 0x00C0

Hodnota větší než \ U0000FFFF může být reprezentována jedním wchar_t, pokud je použito kódování UTF-32 , nebo dvěma, pokud je použito UTF-16.

Důležité je, že univerzální název znaku \ u00C0 vždy označuje znak „À“, bez ohledu na to, v jakém řetězcovém doslovu se používá nebo na používaném kódování. Osmičkové a hexadecimální únikové sekvence vždy označují určité posloupnosti číselných hodnot, bez ohledu na kódování. Proto jsou univerzální názvy znaků komplementární k osmičkovým a hexadecimálním únikovým sekvencím; zatímco osmičkové a hexadecimální únikové sekvence představují kódové jednotky, univerzální názvy znaků představují kódové body , které lze považovat za „logické“ znaky.

Viz také

Reference

Další čtení