Являются ли символы UTF16 (используемые, например, функциями широко-winapi) всегда длиной 2 байта? - PullRequest
5 голосов
/ 11 января 2011

Уточните, пожалуйста, как работает UTF16? Я немного растерялся, учитывая следующие моменты:

  • В C ++ существует статический тип WCHAR, длина которого составляет 2 байта. (всегда 2 байта по длине)
  • Большинство msdn и некоторой другой документации, похоже, предполагают, что длина символов всегда составляет 2 байта. Это может быть только мое воображение, я не могу привести какие-то конкретные примеры, но это только кажется.
  • В C ++ или окнах нет "очень широких" функций или типов символов, поэтому я бы предположил, что UTF16 - это все, что когда-либо необходимо.
  • Насколько мне известно, в юникоде гораздо больше символов, чем в 65535, поэтому им не хватает места в 2 байта.
  • UTF16 представляется более крупной версией UTF8, а символы UTF8 могут иметь различную длину.

Так что, если символ UTF16 не всегда имеет длину 2 байта, как долго это еще может быть? 3 байта? или только кратные 2? И затем, например, если есть функция winapi, которая хочет знать размер широкой строки в символах, и строка содержит 2 символа, каждый из которых имеет длину 4 байта, как размер этой строки в символах рассчитано?

Это 2 символа или 4 символа? (поскольку он имеет длину 8 байт, а каждый WCHAR - 2 байта)

ОБНОВЛЕНИЕ: Теперь я вижу, что подсчет символов не обязательно является стандартным или даже с ++, поэтому я попытаюсь быть более конкретным во втором вопросе о длине в «символах» широкая строка:

В Windows, в частности в Winapi, в их широких функциях (заканчивающихся на W), как считать число символов в строке, состоящей из 2 кодовых точек Юникода, каждая из которых состоит из 2 кодовых единиц (всего 8 байтов) ? Длина такой строки 2 символа (соответствует количеству кодовых точек) или 4 символа (соответствует общему количеству кодовых единиц?)

Или, говоря более обобщенно: что означает определение «количество символов в широкой строке» в Windows, количество кодовых точек или количество кодовых единиц?

Ответы [ 8 ]

8 голосов
/ 11 января 2011

Краткий ответ: Нет.

Размер wchar_t - базовой символьной единицы - не определен Стандартом C ++ (см. Раздел 3.9.1, параграф 5). На практике на платформах Windows длина составляет два байта, а на платформах Linux / Mac - четыре байта.

Кроме того, символы сохраняются в формате, специфичном для порядка байтов. В Windows это обычно означает little-endian, но также допустимо, чтобы wchar_t содержал данные с прямым порядком байтов.

Более того, даже если каждый wchar_t имеет длину в два (или четыре) байта, отдельному глифу (грубо говоря, символу) может потребоваться несколько wchar_t с, и может быть несколько способов его представления.

Типичным примером является символ é (LATIN SMALL LETTER E WITH ACUTE), кодовая точка 0x00E9. Это также может быть представлено как «разложенная» последовательность кодовых точек 0x0065 0x0301 (то есть LATIN SMALL LETTER E, за которой следует COMBINING ACUTE ACCENT). Оба действительны; см. статью в Википедии о эквивалентности Unicode для получения дополнительной информации.

Просто вам нужно знать или выбрать кодировку, которую вы будете использовать. Если вы имеете дело с API-интерфейсами Windows, то легко предположить, что все UTF-16 с прямым порядком байтов хранится в 2-байтовом wchar_t с.

В Linux / Mac UTF-8 (с char s) более распространен, и API обычно принимают UTF-8. wchar_t считается расточительным, потому что он использует 4 байта на символ.

Поэтому для кроссплатформенного программирования вы, возможно, захотите работать с UTF-8 внутри и переходить в UTF-16 на лету при вызове Windows API. Для этого в Windows предусмотрены функции MultiByteToWideChar и WideCharToMultiByte, и вы также можете найти оболочки, упрощающие использование этих функций, такие как ATL и MFC String Conversion Макросы .

Обновление

Вопрос был обновлен, чтобы спросить, что означают API-интерфейсы Windows, когда они запрашивают «количество символов» в строке.

Если API говорит «размер строки в символах», это относится к количеству wchar_t с (или к числу char с, если вы по какой-то причине компилируете в не-Unicode-режиме). В этом конкретном случае вы можете игнорировать тот факт, что символ Unicode может занять более одного wchar_t. Эти API просто хотят заполнить буфер и должны знать, сколько у них места.

5 голосов
/ 11 января 2011

Кажется, у вас несколько неправильное представление.

В C ++ существует статический тип WCHAR, длина которого составляет 2 байта.(всегда 2 байта в длину)

Это неправильно.Предполагая, что вы ссылаетесь на тип c ++ wchar_t - он не всегда имеет длину 2 байта, 4 байта также является общим значением, и нет ограничений, что это могут быть только эти два значения.Если вы не ссылаетесь на это, это не в C ++, но это какой-то платформо-зависимый тип.

  • Не существует "широко широких" функций или типов символов широкоиспользуется в C ++ или Windows, поэтому я предполагаю, что UTF16 - это все, что когда-либо необходимо.

  • UTF16, кажется, является более крупной версией UTF8, а символы UTF8 могут иметь различную длину.

UTF-8 и UTF-16 - это разные кодировки для одного и того же набора символов, поэтому UTF-16 не "больше".Технически схема, используемая в UTF-8, может кодировать больше символов, чем схема, используемая в UTF-16, но как UTF-8 и UTF-16 они кодируют один и тот же набор.

Не использовать термин "характер "легко, когда дело доходит до Unicode. кодовый блок в UTF-16 имеет ширину 2 байта, кодовая точка представлена ​​1 или 2 кодовыми модулями.То, что люди обычно понимают как «символы», отличается и может состоять из одной или нескольких кодовых точек, и если вы, как программист, путаете кодовые точки с символами, могут произойти плохие вещи, такие как http://ideone.com/qV2il

4 голосов
/ 11 января 2011

Windows 'WCHAR имеет длину 16 бит (2 байта).

Код Unicode может быть представлен одним или двумя из этих WCHAR - 16 или 32 бит (2 или 4 байта).

wcslen возвращает число WCHAR единиц в широкой строке, а wcslen_l возвращает количество (зависящих от локали) кодовых точек. Очевидно, wcslen <= wcslen_l.

Символ Unicode может состоять из нескольких комбинированных кодовых точек.

2 голосов
/ 11 января 2011

В C ++ существует статический тип WCHAR, длина которого составляет 2 байта. (всегда 2 байта по длине)

Ну, WCHAR - это вещь MS, а не C ++.
Но для широкого символа есть wchar_t. Хотя это не всегда 2. В системе Linux это обычно 4 байта.

Большинство msdn и некоторой другой документации, похоже, предполагают, что длина символов всегда составляет 2 байта. Это может быть только мое воображение, я не могу привести какие-то конкретные примеры, но это только кажется.

Есть ли они. Я могу в это поверить.

В C ++ или окнах нет "очень широких" функций или типов символов, поэтому я бы предположил, что UTF16 - это все, что когда-либо было необходимо.

C / C ++ не делает никаких предположений относительно кодировки символов. Хотя ОС может. Например, Windows использует UTF-16 в качестве интерфейса, в то время как многие Linus используют UTF-32. Но вы должны прочитать документацию для каждого интерфейса, чтобы знать это явно.

Насколько мне известно, в юникоде гораздо больше символов, чем в 65535, поэтому им не хватает места в 2 байта.

2 байта - все, что вам нужно для чисел 0 -> 65535

Но UCS (кодировка, на которой основана UTF) имеет 20 битов на кодовую точку. Таким образом, некоторые кодовые точки в UTF-16 кодируются как 2 16-байтовых символа (они называются суррогатными парами).

UTF16 представляется более крупной версией UTF8, а символы UTF8 могут иметь различную длину.

UTF-8 / UTF-16 и UTF-32 кодируют один и тот же набор кодовых точек (которые составляют 20 байтов на кодовую точку). UTF-32 - единственный, который имеет фиксированный размер (UTF-16 должен был быть фиксированного размера, но затем они нашли много других символов (например, Klingon), которые нам нужно было закодировать, и у нас закончилось пространство в плоскости 0. Итак мы добавили еще 32 равнины (отсюда и четыре дополнительных бита).

Так что, если символ UTF16 не всегда имеет длину 2 байта, как долго он еще может быть? 3 байта? или только кратные 2?

Это либо 1 16-битный символ, либо 2 16-битные символы.

И затем, например, если есть функция winapi, которая хочет знать размер широкой строки в символах, и строка содержит 2 символа, каждый из которых имеет длину 4 байта, как рассчитывается размер этой строки в символах?

Вы должны идти вперед и вычислять каждого персонажа по одному.

Это 2 символа или 4 символа? (поскольку он имеет длину 8 байт, а каждый WCHAR - 2 байта)

Все системы в вашей системе

2 голосов
/ 11 января 2011

Краткая история: UTF-16 - кодировка переменной длины. Один символ может быть длиной в один или два широких символа.

ОДНАКО, вы вполне можете уйти, рассматривая его как кодировку фиксированной длины, где каждый символ равен одному широкоугольному символу (2 байта). Это формально называется UCS-2, и это было предположение Win32 до Windows NT 4. Кодировка UCS-2 включает в себя практически все живые, мертвые и созданные человеческие языки. И по правде говоря, работа со строками кодирования переменной длины просто отстой. Итерация становится операцией O (n), длина строки не совпадает с размером строки и т. Д. Любой разумный анализ становится проблемой.

Что касается символов UTF-16, которых нет в UCS-2 ... Я знаю только два подмножества, которые теоретически могут возникнуть в реальной жизни. Во-первых, это смайлики - графические смайлики, которые популярны в японской культуре мобильных телефонов. На iPhone есть множество сторонних приложений, которые позволяют вводить их. За исключением мобильных телефонов, они не отображаются должным образом. Другой класс символов - ОЧЕНЬ неясные китайские иероглифы. Те, которые даже большинство китайцев не знают. Все популярные китайские иероглифы находятся внутри UCS-2.

1 голос
/ 11 января 2011

Все символы в Базовой многоязычной плоскости будут иметь длину 2 байта.

Символы в других плоскостях будут кодироваться в 4 байта каждый в виде суррогатная пара .

Очевидно, что если функция не пытается обнаружить суррогатные пары и вслепую рассматривает каждую пару байтов как символ, она будет выдавать ошибки в строках, содержащих такие пары.

1 голос
/ 11 января 2011

Согласно Unicode FAQ это может быть

один или два 16-битных кодовых блока

Windows использует 16-битные символытак как Unicode изначально был 16 бит.Таким образом, у вас нет точной карты - но вам, возможно, удастся обработать все строки, которые вы видите, как содержащие только 16 символов Юникода,

1 голос
/ 11 января 2011

Эта статья в Википедии представляется хорошим введением.

UTF-16 (16-битный формат преобразования Unicode) - это кодировка символов для Unicode, способная кодировать 1 112 064 номера(называемые кодовыми точками) в кодовом пространстве Unicode от 0 до 0x10FFFF.Он выдает результат переменной длины, состоящий из одной или двух 16-битных кодовых единиц на кодовую точку.

...