C99 lub wcześniej
Standard C (C99) zapewnia szerokie znaki i znaki wielobajtowe, ale ponieważ nie ma gwarancji, co te szerokie znaki mogą pomieścić, ich wartość jest nieco ograniczona. Dla danej implementacji zapewniają przydatne wsparcie, ale jeśli Twój kod musi mieć możliwość przemieszczania się między implementacjami, to nie ma wystarczającej gwarancji, że będą przydatne.
W związku z tym podejście zaproponowane przez Hansa van Ecka (polegające na napisaniu otoki wokół biblioteki ICU - International Components for Unicode) jest rozsądne, IMO.
Kodowanie UTF-8 ma wiele zalet, z których jedną jest to, że jeśli nie zepsujesz danych (na przykład skracając je), mogą zostać skopiowane przez funkcje, które nie są w pełni świadome zawiłości UTF-8 kodowanie. To zdecydowanie nie dotyczy wchar_t
.
Pełny Unicode to format 21-bitowy. Oznacza to, że Unicode rezerwuje punkty kodowe od U + 0000 do U + 10FFFF.
Jedną z przydatnych rzeczy w formatach UTF-8, UTF-16 i UTF-32 (gdzie UTF oznacza format transformacji Unicode - patrz Unicode ) jest to, że można konwertować między tymi trzema reprezentacjami bez utraty informacji. Każdy może reprezentować wszystko, co inni mogą reprezentować. Zarówno UTF-8, jak i UTF-16 są formatami wielobajtowymi.
Wiadomo, że UTF-8 jest formatem wielobajtowym, o starannej strukturze, która umożliwia niezawodne znajdowanie początku znaków w ciągu, począwszy od dowolnego punktu ciągu. Znaki jednobajtowe mają ustawiony wysoki bit na zero. Znaki wielobajtowe mają pierwszy znak zaczynający się od jednego ze wzorów bitowych 110, 1110 lub 11110 (dla znaków 2-bajtowych, 3-bajtowych lub 4-bajtowych), a kolejne bajty zawsze zaczynają się od 10. Znaki kontynuacji są zawsze w zakres 0x80 .. 0xBF. Istnieją zasady, zgodnie z którymi znaki UTF-8 muszą być przedstawiane w jak najmniejszym formacie. Jedną z konsekwencji tych reguł jest to, że bajty 0xC0 i 0xC1 (także 0xF5..0xFF) nie mogą występować w prawidłowych danych UTF-8.
U+0000 .. U+007F 1 byte 0xxx xxxx
U+0080 .. U+07FF 2 bytes 110x xxxx 10xx xxxx
U+0800 .. U+FFFF 3 bytes 1110 xxxx 10xx xxxx 10xx xxxx
U+10000 .. U+10FFFF 4 bytes 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
Początkowo oczekiwano, że Unicode będzie 16-bitowym zestawem kodu i wszystko będzie pasować do 16-bitowej przestrzeni kodowej. Niestety, rzeczywisty świat jest bardziej złożony i musiał zostać rozszerzony do obecnego 21-bitowego kodowania.
UTF-16 jest zatem pojedynczym kodem jednostki (słowo 16-bitowe) dla „Basic Multilingual Plane”, co oznacza znaki z punktami kodowymi Unicode U + 0000 .. U + FFFF, ale wykorzystuje dwie jednostki (32-bitowe) dla znaków spoza tego zakresu. Tak więc kod, który działa z kodowaniem UTF-16, musi być w stanie obsługiwać kodowanie o zmiennej szerokości, tak jak musi to być UTF-8. Kody znaków podwójnych nazywane są surogatami.
Surogaty to punkty kodowe z dwóch specjalnych zakresów wartości Unicode, zarezerwowanych do użytku jako wartości wiodące i końcowe sparowanych jednostek kodu w UTF-16. Wiodące, zwane również wysokimi, surogaty są od U + D800 do U + DBFF, a końcowe lub niskie, zastępcze są od U + DC00 do U + DFFF. Nazywa się je surogatami, ponieważ nie reprezentują postaci bezpośrednio, ale tylko jako parę.
Oczywiście UTF-32 może zakodować dowolny punkt kodu Unicode w pojedynczej jednostce pamięci. Jest wydajna do obliczeń, ale nie do przechowywania.
Więcej informacji można znaleźć na stronach internetowych ICU i Unicode.
C11 i <uchar.h>
Standard C11 zmienił zasady, ale nie wszystkie implementacje nadążyły za zmianami nawet teraz (połowa 2017 roku). Standard C11 podsumowuje zmiany dotyczące obsługi Unicode jako:
- Znaki i ciągi znaków Unicode (
<uchar.h>
) (pierwotnie określone w ISO / IEC TR 19769: 2004)
Poniżej przedstawiono minimalny zarys funkcjonalności. Specyfikacja obejmuje:
6.4.3 Uniwersalne nazwy znaków
Składnia
nazwa-znaku-uniwersalnego:
\u
quad-quad
\U
hex-quad hex-quad
hex-quad:
cyfra-szesnastkowa cyfra-szesnastkowa cyfra-szesnastkowa
7.28 Narzędzia Unicode <uchar.h>
Nagłówek <uchar.h>
deklaruje typy i funkcje do manipulowania znakami Unicode.
Deklarowane typy to mbstate_t
(opisane w 7.29.1) i size_t
(opisane w 7.19);
char16_t
który jest typem liczby całkowitej bez znaku używanej dla znaków 16-bitowych i jest tego samego typu, co uint_least16_t
(opisany w 7.20.1.2); i
char32_t
który jest typem liczby całkowitej bez znaku używanej dla znaków 32-bitowych i jest tego samego typu, co uint_least32_t
(również opisany w 7.20.1.2).
(Tłumaczenie odsyłaczy: <stddef.h>
definiuje size_t
,
<wchar.h>
definiuje mbstate_t
i <stdint.h>
definiuje uint_least16_t
i uint_least32_t
.) <uchar.h>
Nagłówek definiuje również minimalny zestaw (uruchamialnych) funkcji konwersji:
mbrtoc16()
c16rtomb()
mbrtoc32()
c32rtomb()
Istnieją reguły określające, które znaki Unicode mogą być używane w identyfikatorach przy użyciu notacji \unnnn
lub \U00nnnnnn
. Może być konieczne aktywne aktywowanie obsługi takich znaków w identyfikatorach. Na przykład GCC wymaga, -fextended-identifiers
aby zezwolić na te identyfikatory.
Zwróć uwagę, że macOS Sierra (10.12.5), żeby wymienić tylko jedną platformę, nie obsługuje <uchar.h>
.