Из того, что я понимаю, char
безопасен для размещения символов ASCII, тогда как char16_t
и char32_t
безопасны для размещения символов из Юникода, один для 16-битного сорта, а другой для 32-битного сорта ( Должен ли я сказать "a" вместо "the"?). Но меня тогда интересует, какова цель, стоящая за wchar_t
. Должен ли я когда-либо использовать этот тип в новом коде, или он просто поддерживает старый код? Какова была цель wchar_t
в старом коде, если из того, что я понимаю, его размер не имел гарантии быть больше, чем char
? Уточнение будет приятным!
Char vs wchar_t vs char16_t vs char32_t (С++ 11)
Ответ 1
char
предназначен для 8-разрядных кодовых блоков, char16_t
предназначен для 16-разрядных кодовых блоков, а char32_t
- для 32-разрядных кодовых блоков. Любой из них может использоваться для "Unicode"; UTF-8 использует 8-битные кодовые единицы, UTF-16 использует 16-битные кодовые единицы, а UTF-32 использует 32-битные кодовые единицы.
Гарантия на wchar_t
заключалась в том, что любой символ, поддерживаемый в локали, может быть преобразован из char
в wchar_t
, и любое представление, используемое для char
, будь то несколько байтов, коды сдвига, что вы, wchar_t
будет единственным, отличным значением. Целью этого было то, что тогда вы могли бы манипулировать строками wchar_t
так же, как простые алгоритмы, используемые с ASCII.
Например, преобразование ascii в верхний регистр выглядит следующим образом:
auto loc = std::locale("");
char s[] = "hello";
for (char &c : s) {
c = toupper(c, loc);
}
Но это не будет обрабатывать преобразование всех символов в UTF-8 в верхний регистр или все символы в другой кодировке, например Shift-JIS. Люди хотели иметь возможность интернационализировать этот код следующим образом:
auto loc = std::locale("");
wchar_t s[] = L"hello";
for (wchar_t &c : s) {
c = toupper(c, loc);
}
Таким образом, каждый wchar_t
является "символом", и если он имеет версию в верхнем регистре, он может быть напрямую преобразован. К сожалению, это не работает все время; Например, на некоторых языках существуют такие странности, как немецкая буква ß, где верхняя версия на самом деле представляет собой два символа SS вместо одного символа.
Таким образом, интернационализированная обработка текста по своей сути сложнее, чем ASCII, и не может быть действительно упрощена в том, как предназначены дизайнеры wchar_t
. Как таковые wchar_t
и широкие символы вообще не имеют большого значения.
Единственная причина для их использования заключается в том, что они были испечены в некоторых API и платформах. Тем не менее, я предпочитаю придерживаться UTF-8 в своем собственном коде даже при разработке на таких платформах и просто конвертировать на границах API любую кодировку.
Ответ 2
Тип wchar_t
был помещен в стандарт, когда Unicode обещал создать 16-битное представление. Большинство поставщиков предпочитают делать wchar_t
32 бита, но один крупный поставщик решил сделать это 16 бит. Поскольку Unicode использует более 16 бит (например, 20 бит), было сочтено, что у нас должны быть лучшие типы символов.
Цель char16_t
- представлять UTF16 и char32_t
предназначена для непосредственного представления символов Unicode. Тем не менее, в системах, использующих wchar_t
как часть их основного интерфейса, вы будете придерживаться wchar_t
. Если вы не ограничены, я лично использовал бы char
для представления Unicode с использованием UTF8. Проблема с char16_t
и char32_t
заключается в том, что они не полностью поддерживаются, даже в стандартной библиотеке С++: например, нет потоков, поддерживающих эти типы напрямую, и это больше работает, чем просто создание экземпляра потока для этих типов.