UTF-16 фиксированной или переменной ширины? Я получил разные результаты из разных источников:
С http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF :
UTF-16 хранит символы Unicode в шестнадцати разрядных блоках.
С http://en.wikipedia.org/wiki/UTF-16/UCS-2 :
UTF-16 (16-битный формат преобразования Unicode) - это кодировка символов для Unicode, способная кодировать 1 112 064 [1] числа (называемых кодовыми точками) в кодовом пространстве Unicode от 0 до 0x10FFFF. Он выдает результат переменной длины, состоящий из одного или двух 16-битных кодовых блоков на кодовую точку.
Из первого источника
UTF-8 также имеет преимущество в том, что единицей кодирования является байт, поэтому нет проблем с порядком байтов.
Почему у UTF-8 нет проблемы порядка следования байтов? Это переменная ширина, и один символ может содержать более одного байта, поэтому я думаю, что порядок следования байтов все еще может быть проблемой?
Спасибо и всего наилучшего!
источник
Ответы:
Похоже, вы неправильно понимаете, что такое порядковый номер. Вот краткое резюме.
32-разрядное целое число занимает 4 байта. Теперь мы знаем логический порядок этих байтов. Если у вас есть 32-разрядное целое число, вы можете получить старший байт этого с помощью следующего кода:
Это все хорошо. Проблема начинается с того, как различное оборудование хранит и извлекает целые числа из памяти.
В порядке с прямым порядком байтов 4-байтовый фрагмент памяти, который вы читаете как 32-разрядное целое число, будет прочитан, причем первый байт будет старшим байтом:
В порядке Little Endian 4-байтовый фрагмент памяти, который вы читаете как 32-разрядное целое число, будет читаться с первым байтом, являющимся младшим байтом:
Если у вас есть указатель на указатель на 32-битное значение, вы можете сделать это:
Согласно C / C ++, результат этого не определен. Это может быть 0x81. Или это может быть 0x32. Технически, он может вернуть все что угодно, но для реальных систем он вернет одну или другую.
Если у вас есть указатель на адрес памяти, вы можете прочитать этот адрес как 32-разрядное значение, 16-разрядное значение или 8-разрядное значение. На старшей байтовой машине указатель указывает на старший байт; на машине с прямым порядком байтов указатель указывает на младший байт.
Обратите внимание, что это все о чтении и записи в / из памяти. Это не имеет ничего общего с внутренним кодом C / C ++. Первая версия кода, которую C / C ++ не объявляет как неопределенную, всегда будет работать для получения старшего байта.
Проблема в том, когда вы начинаете читать потоки байтов. Например, из файла.
16-битные значения имеют те же проблемы, что и 32-битные; у них просто 2 байта вместо 4. Следовательно, файл может содержать 16-битные значения, хранящиеся в порядке с прямым или прямым порядком байтов.
UTF-16 определяется как последовательность 16-битных значений . По сути, это
uint16_t[]
. Каждая единица кода является 16-битным значением. Следовательно, для правильной загрузки UTF-16 вы должны знать, что такое порядок данных.UTF-8 определяется как последовательность 8-битных значений . Это
uint8_t[]
. Каждая единица кода имеет размер 8 битов: один байт.Теперь, как UTF-16 и UTF-8 позволяют несколько блоков кода (16-битные или 8-разрядные значения) , чтобы объединить вместе , чтобы сформировать элемент кода Unicode (а «символ», но это не правильный термин, это упрощение ). Порядок этих кодовых блоков , которые образуют элемент кода диктуется UTF-16 и UTF-8 кодировке.
При обработке UTF-16 вы читаете 16-битное значение, выполняя любое обратное преобразование. Затем вы обнаруживаете, если это суррогатная пара; если это так, тогда вы читаете еще одно 16-битное значение, объединяете их, и из этого вы получаете значение кодовой точки Unicode.
При обработке UTF-8 вы читаете 8-битное значение. Преобразование в обратный порядок не возможно, поскольку существует только один байт. Если первый байт обозначает многобайтовую последовательность, то вы читаете некоторое количество байтов, как предписано многобайтовой последовательностью. Каждый отдельный байт является байтом и, следовательно, не имеет порядка байтов. Порядок этих байтов в последовательности, так же , как порядок суррогатных пар в UTF-16, определяется UTF-8.
Таким образом, с UTF-8 не может быть проблем с порядком байтов.
источник
Ответ Джереми Бэнкса верен, но не касается порядка байтов.
Когда вы используете UTF-16, большинство глифов хранятся с использованием двухбайтового слова - но когда слово хранится в файле на диске, какой порядок вы используете для хранения составляющих байтов?
Например, глиф CJK (китайский) для слова «вода» имеет кодировку UTF-16 в шестнадцатеричном формате 6C34. Когда вы записываете это как два байта на диск, вы записываете это как "big-endian" (два байта - 6C 34)? Или вы пишете это как "little-endian (два байта 34 6C)?
В UTF-16 оба порядка являются законными, и вы обычно указываете, какой из файлов имеет файл, делая первое слово в файле меткой порядка байтов (BOM), которая для кодирования с прямым порядком байтов равна FE FF, а для байтов с прямым порядком байтов кодировка FF FE.
UTF-32 имеет ту же проблему и то же решение.
UTF-8 не имеет этой проблемы, потому что это переменная длина, и вы эффективно пишете последовательность байтов глифа, как если бы она была с прямым порядком байтов. Например, буква «P» всегда кодируется с использованием одного байта - 80 -, а символ замены всегда кодируется с использованием двухбайтовой FF FD в этом порядке.
Некоторые программы помещают трехбайтовый индикатор (EF BB BF) в начало файла UTF-8, и это помогает отличить UTF-8 от аналогичных кодировок, таких как ASCII, но это не очень распространено, за исключением MS Windows.
источник