mbstowcs()
и wcstombs()
не обязательно конвертируются в UTF-16 или UTF-32, они конвертируются в wchar_t
и в любую кодировку wchar_t
.Все локали Windows используют двухбайтовую wchar_t
и UTF-16 в качестве кодировки, но другие основные платформы используют 4-байтовую wchar_t
с UTF-32 (или даже кодировку не-Unicode для некоторых локалей).Платформа, которая поддерживает только однобайтовые кодировки, может даже иметь один байт wchar_t
и иметь кодировку, различающуюся по локали.Так что wchar_t
кажется мне плохим выбором для переносимости и Unicode.*
В C ++ 11 были добавлены некоторые лучшие опции;новые специализации std :: codecvt, новые классы codecvt и новый шаблон, чтобы сделать их использование для преобразований очень удобным.
Сначала новый класс шаблона для использования codecvt - это std :: wstring_convert.После того, как вы создали экземпляр класса std :: wstring_convert, вы можете легко конвертировать строки:
std::wstring_convert<...> convert; // ... filled in with a codecvt to do UTF-8 <-> UTF-16
std::string utf8_string = u8"This string has UTF-8 content";
std::u16string utf16_string = convert.from_bytes(utf8_string);
std::string another_utf8_string = convert.to_bytes(utf16_string);
Чтобы выполнить другое преобразование, вам просто нужны разные параметры шаблона, один из которых является аспектом codecvt.,Вот некоторые новые аспекты, которые легко использовать с wstring_convert:
std::codecvt_utf8_utf16<char16_t> // converts between UTF-8 <-> UTF-16
std::codecvt_utf8<char32_t> // converts between UTF-8 <-> UTF-32
std::codecvt_utf8<char16_t> // converts between UTF-8 <-> UCS-2 (warning, not UTF-16! Don't bother using this one)
Примеры использования:
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::string a = convert.to_bytes(u"This string has UTF-16 content");
std::u16string b = convert.from_bytes(u8"blah blah blah");
Новые специализации std :: codecvt немного сложнее использовать, потому чтоу них есть защищенный деструктор.Чтобы обойти это, вы можете определить подкласс, который имеет деструктор, или вы можете использовать шаблонную функцию std :: use_facet, чтобы получить существующий экземпляр codecvt.Кроме того, проблема с этими специализациями заключается в том, что вы не можете использовать их в Visual Studio 2010, поскольку специализация шаблонов не работает с типами typedef и этот компилятор определяет char16_t и char32_t как typedefs.Вот пример определения вашего собственного подкласса codecvt:
template <class internT, class externT, class stateT>
struct codecvt : std::codecvt<internT,externT,stateT>
{ ~codecvt(){} };
std::wstring_convert<codecvt<char16_t,char,std::mbstate_t>,char16_t> convert16;
std::wstring_convert<codecvt<char32_t,char,std::mbstate_t>,char32_t> convert32;
Специализация char16_t конвертирует между UTF-16 и UTF-8.Специализация char32_t, UTF-32 и UTF-8.
Обратите внимание, что эти новые преобразования, предоставляемые C ++ 11, не включают никакого способа прямого преобразования между UTF-32 и UTF-16.Вместо этого вам просто нужно объединить два экземпляра std :: wstring_convert.
***** Я подумал, что добавлю заметку о wchar_t и его назначении, чтобы подчеркнуть, почему он вообще не должен бытьиспользуется для Unicode или переносимого интернационализированного кода.Ниже приведена краткая версия моего ответа https://stackoverflow.com/a/11107667/365496
Что такое wchar_t?
wchar_t определяется так, что кодировка char любой локали может быть преобразована в wchar_t, где каждый wchar_t представляет ровно одну кодовую точку:
Тип wchar_t - это отдельный тип, значения которого могут представлять разные коды для всех членов наибольшего расширенного набора символов, указанного среди поддерживаемых локалей (22.3.1).- [basic.fundamental] 3.9.1 / 5
Этот не требует, чтобы wchar_t был достаточно большим, чтобы представлять любой символ из всех языков одновременно,То есть кодировка, используемая для wchar_t, может отличаться в разных локалях.Это означает, что вы не можете обязательно преобразовать строку в wchar_t, используя один языковой стандарт, а затем преобразовать обратно в тип char, используя другой языковой стандарт.
Поскольку это, по-видимому, основное применение на практике для wchar_t, вы можете спросить, для чего это хорошо, еслиэто не так.
Первоначальная цель и цель wchar_t заключалась в том, чтобы упростить обработку текста, определив его так, чтобы он требовал однозначного сопоставления кодовых единиц строки с символами текста, что позволяетиспользовать те же простые алгоритмы, которые используются со строками ascii для работы с другими языками.
К сожалению, требования для wchar_t предполагают взаимно-однозначное сопоставление символов и кодовых точек для достижения этой цели.Unicode нарушает это предположение, поэтому вы не можете безопасно использовать wchar_t для простых текстовых алгоритмов.
Это означает, что переносимое программное обеспечение не может использовать wchar_t либо в качестве общего представления для текста между локалями, либо для включения использования простоготекстовые алгоритмы.
Какая польза от wchar_t сегодня?
Не так много, для переносимого кода в любом случае. Если определено __STDC_ISO_10646__
, то значения wchar_t напрямую представляют кодовые точки Unicode с одинаковыми значениями во всех локалях. Это делает безопасным выполнение преобразований между локалями, упомянутых ранее. Однако вы не можете полагаться только на него, чтобы решить, что вы можете использовать wchar_t таким образом, потому что, хотя большинство платформ Unix определяют его, Windows этого не делает, хотя Windows использует один и тот же языковой стандарт wchar_t во всех локалях.
Причина, по которой Windows не определяет __STDC_ISO_10646__
Я думаю, это потому, что Windows использует UTF-16 в качестве кодировки wchar_t, и потому что UTF-16 использует суррогатные пары для представления кодовых точек, больших, чем U + FFFF, что означает, что UTF-16 не удовлетворяет требованиям для __STDC_ISO_10646__
.
Для конкретного кода платформы wchar_t может быть более полезным. По сути, это требуется в Windows (например, некоторые файлы просто не могут быть открыты без использования имен файлов wchar_t), хотя, насколько я знаю, Windows является единственной платформой, где это верно (поэтому, возможно, мы можем думать о wchar_t как о Windows_char_t).
Оглядываясь назад, wchar_t явно не полезен для упрощения обработки текста или для хранения текста, не зависящего от локали. Переносимый код не должен пытаться использовать его для этих целей.