Czy UTF-16 ma stałą szerokość czy zmienną szerokość? Otrzymałem różne wyniki z różnych źródeł:
From http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF :
UTF-16 przechowuje znaki Unicode w szesnastobitowych porcjach.
From http://en.wikipedia.org/wiki/UTF-16/UCS-2 :
UTF-16 (16-bitowy format transformacji Unicode) to kodowanie znaków dla Unicode, zdolne do kodowania 1 112 064 [1] liczb (zwanych punktami kodowymi) w przestrzeni kodu Unicode od 0 do 0x10FFFF. Daje wynik o zmiennej długości jednej lub dwóch 16-bitowych jednostek kodu na punkt kodowy.
Z pierwszego źródła
Zaletą UTF-8 jest to, że jednostką kodowania jest bajt, więc nie występują problemy z kolejnością bajtów.
Dlaczego UTF-8 nie ma problemu z kolejnością bajtów? Ma zmienną szerokość, a jeden znak może zawierać więcej niż jeden bajt, więc myślę, że kolejność bajtów nadal może stanowić problem?
Dziękuję i pozdrawiam!
źródło
Odpowiedzi:
Wygląda na to, że nie rozumiesz, jakie są problemy związane z endianem. Oto krótkie podsumowanie.
32-bitowa liczba całkowita zajmuje 4 bajty. Teraz znamy logiczną kolejność tych bajtów. Jeśli masz 32-bitową liczbę całkowitą, możesz uzyskać jej wyższy bajt za pomocą następującego kodu:
Wszystko dobrze i dobrze. Problem zaczyna się od tego, jak różne urządzenia zapisują i pobierają liczby całkowite z pamięci.
W kolejności Big Endian 4 bajtowa pamięć, którą odczytujesz jako 32-bitową liczbę całkowitą, zostanie odczytana, a pierwszy bajt będzie bajtem najwyższym:
W kolejności Little Endian 4-bajtowa pamięć, którą odczytujesz jako 32-bitową liczbę całkowitą, zostanie odczytana, przy czym pierwszy bajt będzie bajtem niższym :
Jeśli masz wskaźnik do wskaźnika do wartości 32-bitowej, możesz to zrobić:
Według C / C ++ wynik tego jest niezdefiniowany. Może to być 0x81. Lub może to być 0x32. Technicznie rzecz biorąc, może zwrócić wszystko, ale w przypadku prawdziwych systemów zwróci jedno lub drugie.
Jeśli masz wskaźnik do adresu pamięci, możesz odczytać ten adres jako wartość 32-bitową, 16-bitową lub 8-bitową. Na dużej maszynie Endian wskaźnik wskazuje na wysoki bajt; na małej maszynie Endian wskaźnik wskazuje na niski bajt.
Zauważ, że chodzi o czytanie i pisanie do / z pamięci. Nie ma to nic wspólnego z wewnętrznym kodem C / C ++. Pierwsza wersja kodu, ta, której C / C ++ nie deklaruje jako niezdefiniowany, zawsze będzie działać, aby uzyskać wysoki bajt.
Problem polega na tym, gdy zaczynasz czytać strumienie bajtów. Tak jak z pliku.
Wartości 16-bitowe mają te same problemy, co wartości 32-bitowe; mają po prostu 2 bajty zamiast 4. Dlatego plik może zawierać 16-bitowe wartości przechowywane w dużej lub małej kolejności.
UTF-16 jest zdefiniowany jako sekwencja 16-bitowych wartości . Skutecznie jest to
uint16_t[]
. Każda pojedyncza jednostka kodu ma wartość 16-bitową. Dlatego, aby poprawnie załadować UTF-16, musisz wiedzieć, co to jest endianność danych.UTF-8 jest zdefiniowany jako ciąg wartości 8-bitowych . To jest
uint8_t[]
. Każda pojedyncza jednostka kodu ma 8 bitów: jeden bajt.Teraz zarówno UTF-16, jak i UTF-8 pozwalają na połączenie wielu jednostek kodu (wartości 16-bitowe lub 8-bitowe) w celu utworzenia punktu kodowego Unicode („znak”, ale to nie jest poprawny termin; jest to uproszczenie ). Kolejność tych jednostek kodu, które tworzą kodowy jest podyktowane UTF-16 i UTF-8 kodowania.
Podczas przetwarzania UTF-16 odczytujesz 16-bitową wartość, robiąc wszystko, czego potrzeba konwersja endian. Następnie wykrywasz, czy jest to para zastępcza; jeśli tak, to odczytujesz kolejną 16-bitową wartość, łączysz obie, a następnie otrzymujesz wartość punktu kodowego Unicode.
Podczas przetwarzania UTF-8 odczytujesz wartość 8-bitową. Żadna konwersja endiana nie jest możliwa, ponieważ jest tylko jeden bajt. Jeśli pierwszy bajt oznacza sekwencję wielobajtową, to odczytujesz pewną liczbę bajtów, zgodnie z sekwencją wielobajtową. Każdy pojedynczy bajt jest bajtem i dlatego nie ma konwersji typu endian. Kolejność tych bitów w sekwencji, tak jak kolejność pary zastępczych UTF-16 jest określona przez UTF-8.
Tak więc nie może być żadnych problemów endian z UTF-8.
źródło
Odpowiedź Jeremy Banks jest poprawna, ale nie dotyczyła kolejności bajtów.
Kiedy używasz UTF-16, większość glifów jest przechowywana przy użyciu dwubajtowego słowa - ale kiedy to słowo jest przechowywane w pliku dyskowym, w jakiej kolejności zapisujesz bajty składowe?
Na przykład glif CJK (chiński) dla słowa „woda” ma kodowanie UTF-16 w systemie szesnastkowym 6C34. Kiedy zapisujesz to jako dwa bajty na dysk, czy zapisujesz to jako „big-endian” (dwa bajty to 6C 34)? A może piszesz to jako „little-endian (dwa bajty to 34 6C)?
W przypadku UTF-16 oba porządki są uzasadnione i zwykle wskazuje się, które z nich ma plik, czyniąc pierwsze słowo w pliku znakiem Byte Order Mark (BOM), który dla kodowania big-endian to FE FF, a dla little-endian kodowanie to FF FE.
UTF-32 ma ten sam problem i to samo rozwiązanie.
UTF-8 nie ma tego problemu, ponieważ ma zmienną długość, a Ty efektywnie zapisujesz sekwencję bajtów glifów, jakby to był little-endian. Na przykład litera „P” jest zawsze kodowana przy użyciu jednego bajtu - 80 - a znak zastępujący jest zawsze kodowany przy użyciu dwóch bajtów FF FD w tej kolejności.
Niektóre programy umieszczają trzy bajtowy wskaźnik (EF BB BF) na początku pliku UTF-8, co pomaga odróżnić UTF-8 od podobnych kodowań, takich jak ASCII, ale nie jest to zbyt częste, z wyjątkiem MS Windows.
źródło