Кодировка Unicode для строковых литералов в C ++ 11

В ответ на связанный с этим вопрос, я хотел бы спросить о новые типы символьных и строковых литералов в C ++ 11. Кажется, что теперь у нас есть четыре типа символов и пять видов строковых литералов. Типы персонажей:

char     a =  '\x30';         // character, no semantics
wchar_t  b = L'\xFFEF';       // wide character, no semantics
char16_t c = u'\u00F6';       // 16-bit, assumed UTF16?
char32_t d = U'\U0010FFFF';   // 32-bit, assumed UCS-4

И строковые литералы:

char     A[] =  "Hello\x0A";         // byte string, "narrow encoding"
wchar_t  B[] = L"Hell\xF6\x0A";      // wide string, impl-def'd encoding
char16_t C[] = u"Hell\u00F6";        // (1)
char32_t D[] = U"Hell\U000000F6\U0010FFFF"; // (2)
auto     E[] = u8"\u00F6\U0010FFFF"; // (3)

Вопрос в следующем: можно ли свободно комбинировать ссылки на символы _3 _ / _ 4 _ / _ 5_ со всеми типами строк? Все ли строковые типы имеют фиксированную ширину, т.е. массивы содержат ровно столько элементов, сколько указано в литерале, или ссылки на _6 _ / _ 7 _ / _ 8_ расширяются до переменного числа байтов? Имеют ли строки u"" и u8"" семантику кодирования, например могу я сказать char16_t x[] = u"\U0010FFFF", и кодовая точка, отличная от BMP, кодируется в двухэлементную последовательность UTF16? И аналогично для u8? Можно ли в (1) писать одинокие суррогаты с \u? Наконец, осведомлены ли какие-либо строковые функции о кодировании (т.е. они распознают символы и могут обнаруживать недопустимые последовательности байтов)?

Это немного открытый вопрос, но я хотел бы получить как можно более полное представление о новых возможностях кодирования UTF и типов в новом C ++ 11.


person Kerrek SB    schedule 22.07.2011    source источник
comment
GCC кодирует u"\U0010FFFF" в суррогатную пару.   -  person kennytm    schedule 23.07.2011


Ответы (1)


Можно ли свободно комбинировать ссылки на символы \ x / \ u / \ U со всеми типами строк?

Нет. \x можно использовать в чем угодно, но \u и \U можно использовать только в строках, специально закодированных в UTF. Однако для любой строки в кодировке UTF можно использовать \u и \U по своему усмотрению.

Все ли строковые типы имеют фиксированную ширину, т.е. массивы содержат ровно столько элементов, сколько указано в литерале, или ссылки на \ x / \ u / \ U расширяются до переменного числа байтов?

Не так, как ты имеешь в виду. \x, \u и \U преобразуются на основе кодировки строки. Количество значений этих «кодовых единиц» (используя термины Unicode. A char16_t - это кодовая единица UTF-16) зависит от кодировки содержащей строку. Литерал u8"\u1024" создаст строку, содержащую 2 char плюс нулевой терминатор. Литерал u"\u1024" создаст строку, содержащую 1 char16_t плюс нулевой терминатор.

Количество используемых кодовых единиц основано на кодировке Unicode.

Имеют ли строки u "" и u8 "" семантику кодирования, например могу я сказать char16_t x [] = u "\ U0010FFFF", и кодовая точка, отличная от BMP, будет закодирована в двухэлементную последовательность UTF16?

u"" создает строку в кодировке UTF-16. u8"" создает строку в кодировке UTF-8. Они будут закодированы в соответствии со спецификацией Unicode.

В (1) могу ли я писать одинокие суррогаты с \ u?

Точно нет. Спецификация прямо запрещает использование суррогатных пар UTF-16 (0xD800-0xDFFF) в качестве кодовых точек для \u или \U.

Наконец, осведомлены ли какие-либо строковые функции о кодировании (т.е. они распознают символы и могут обнаруживать недопустимые последовательности байтов)?

Точно нет. Что ж, позвольте мне перефразировать это.

std::basic_string не работает с кодировками Unicode. Они определенно могут хранить строки в кодировке UTF. Но они могут думать о них только как о последовательностях char, char16_t или char32_t; они не могут думать о них как о последовательности кодовых точек Unicode, которые закодированы с помощью определенного механизма. basic_string::length() вернет количество кодовых единиц, а не кодовых точек. И очевидно, что строковые функции стандартной библиотеки C совершенно бесполезны.

Однако следует отметить, что «длина» строки Unicode не означает количество кодовых точек. Некоторые кодовые точки объединяют «символы» (неудачное имя), которые комбинируются с предыдущей кодовой точкой. Таким образом, несколько кодовых точек могут отображаться на один визуальный символ.

Фактически Iostreams могут читать / записывать значения в кодировке Unicode. Для этого вам нужно будет использовать локаль, чтобы указать кодировку и правильно внедрить ее в различные места. Легче сказать, чем сделать, и у меня нет кода, чтобы показать вам, как это сделать.

person Nicol Bolas    schedule 23.07.2011
comment
@Philipp: Нет, это не так. Unicode специально резервирует их для суррогатов UTF-16 . И, как уже говорилось, спецификация C ++ 0x говорит, что компиляция завершится неудачно, если вы попытаетесь указать кодовую точку в этом диапазоне. - person Nicol Bolas; 24.07.2011
comment
Ваша ссылка доказывает, что они являются кодовыми точками. Если вы не доверяете Википедии, прочтите определения 9 и 10 в главе 3 Стандарта. Однако суррогатные кодовые точки в строковых литералах запрещены в C ++ 0x правилом § 2.4 / 2. - person Philipp; 25.07.2011
comment
После прочтения я также подтверждаю, что суррогатные кодовые точки принимаются в строковых литералах. - person George Kourtis; 27.07.2014
comment
В C11 \x не может использоваться ни с чем, например U + 1F984 не будет работать с префиксом \ x, а \u и \U не могут использоваться с управляющими символами ASCII, по крайней мере, в Clang. - person MarcusJ; 07.04.2018