Ответ 1
Примечание: Вау... По-видимому, кто-то решил, что ПОЧТИ все ответы заслуживают понижения, даже когда они правильны... Я взял на себя перемоделирование их, чтобы сбалансировать понижение...
Посмотрим, есть ли у меня собственный понижающий мотив...: -/
Изменить: REJOICE!!!
Девять часов назад кто-то (возможно, тот, кто отклонил каждый ответ, но Павел Радзивиловский), отменил этот ответ. Конечно, без каких-либо комментариев, указывающих на то, что неправильно с моим ответом.
\ о /
1 - Как выполнить миграцию в Windows Unicode?
Какие изменения мне необходимо внести для переноса этого кода, чтобы он работал в экосистеме библиотек с поддержкой Unicode и Unicode в Visual Studio? (Мне не нужна настоятельная необходимость работать с ASCII и Unicode, это может быть чистый Unicode.)
1.a - Моя кодовая база большая, я не могу сделать это за один шаг!
Представьте, что вы хотите сделать это постепенно (потому что ваше приложение не мало).
У меня была такая же проблема в моей команде: я хотел создать готовый код Unicode, сосуществующий с кодом, который не был готов к Unicode.
Для этого вы должны использовать заголовок MS tchar.h
и использовать его возможности. Используя ваши собственные примеры:
-
"Hello World"
---- >_T("Hello World")
-
char
type ---- >TCHAR
type -
char *
указатели на выделенные строки C ---- >TCHAR *
указатели -
std::string
type --- > Это сложно, потому что вы должны создать свой собственныйstd::tstring
- помните, что sizeof (char) может отличаться от sizeof (TCHAR), поэтому обновите свои mallocs и новые [], также
1.b - Ваш собственный заголовок tstring.hpp
Чтобы обрабатывать STL с моим компилятором (в то время я работал над Visual С++ 2003, поэтому ваш пробег может меняться), я должен предоставить заголовок tstring.hpp
, который является как кросс-платформой, так и позволяет пользователю использовать tstring, tiostream и т.д. Я не могу разместить полный источник здесь, но я дам выдержку, которая позволит вам создавать свои собственные:
namespace std
{
#ifdef _MSC_VER
#ifdef UNICODE
typedef wstring tstring ;
typedef wistream tistream ;
// etc.
#else // Not UNICODE
typedef string tstring ;
typedef istream tistream ;
// etc.
#endif
#endif
} // namespace std
Обычно не разрешается загрязнять пространство имен std
, но я думаю, что это нормально (и оно было протестировано нормально).
Таким образом, вы можете пристроить большинство конструктов iostreams STL/С++ с помощью t
и подготовить его в Unicode (в Windows).
1.c - Сделано!!!
Теперь вы можете переключиться из режима ANSI в режим UNICODE, указав UNICODE
и _UNICODE
, как правило, в настройках проекта (я помню на Visual С++ 2008, что есть записи на первых страницах настроек именно для этого).
Мой совет заключается в том, что у вас, вероятно, есть режим "Отладка" и "Релиз" на вашем проекте Visual С++, чтобы создать "отладочный Unicode" и "Release Unicode", полученный из них, где описанные выше макросы определены.
Таким образом, вы сможете создавать ANSI и UNICODE файлы.
1.d - Теперь все (или должно быть) Unicode!
Если вы хотите, чтобы ваше приложение было межплатформенным, игнорируйте этот раздел.
Теперь либо вы можете изменить всю свою базу кода за один шаг, либо уже преобразовали всю свою кодовую базу для использования функций tchar.h
, описанных выше, теперь вы можете удалить все макросы из своего кода:
-
_T("Hello World")
---- >L"Hello World"
-
TCHAR
type ---- >wchar_t
type -
TCHAR *
указатели на выделенные строки C ---- >wchar_t *
указатели -
std::tstring
type --- >std::wstring
type и т.д.
1.e - Помните, что символы UTF-16 могут быть 1 или 2 wchar_t в Windows!
Одним из распространенных заблуждений в Windows является вера в символ wchar_t - это один символ Юникода. Это неверно, так как некоторые символы Unicode представлены двумя wchar_t.
Таким образом, любой код, который опирается на один char
, являющийся одним глифом, потенциально может быть нарушен, если вы используете символы Unicode не из BMP.
2 - Выполнение перекрестной платформы?
Можно ли это сделать и на платформе независимо? (т.е. не используя типы Microsoft.)
Теперь это была сложная часть.
Linux (я не знаю других ОС, но это должно быть легко сделать из решения Linux или Windows) теперь готово к использованию Unicode, тип char
должен содержать значение UTF-8.
Это означает, что ваше приложение, однажды скомпилированное, например, на моем Ubuntu 10.04, по умолчанию является Unicode.
2.a - Помните, что символы UTF-8 могут быть 1, 2, 3 или 4 char широкими в Linux!
Конечно, совет выше по UTF-16 и широким символам здесь еще более критичен:
Для символа Unicode может понадобиться от 1 до 4 символов char
. Таким образом, любой используемый вами код полагается на предположение, что каждый char
является незаменимым символом Unicode.
2.b - В Linux нет tchar.h
Мое решение: напишите.
Вам нужно только определить префиксные символы 't' для отображения над нормальными, как показано в этом примере:
#ifdef __GNUC__
#ifdef __cplusplus
extern "C" {
#endif
#define _TEOF EOF
#define __T(x) x
// etc.
#define _tmain main
// etc.
#define _tprintf printf
#define _ftprintf fprintf
// etc.
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
#ifdef __cplusplus
}
#endif
#endif // __GNUC__
... и включить его в Linux вместо того, чтобы включать tchar.h
из Windows.
2.c - в Linux нет tstring
Конечно, сопоставление STL, сделанное выше для Windows, должно быть завершено для обработки случая Linux:
namespace std
{
#ifdef _MSC_VER
#ifdef UNICODE
typedef wstring tstring ;
typedef wistream tistream ;
// etc.
#else // Not UNICODE
typedef string tstring ;
typedef istream tistream ;
// etc.
#endif
#elif defined(__GNUC__)
typedef string tstring ;
typedef istream tistream ;
// etc.
#endif
} // namespace std
Теперь вы можете использовать _T("Hello World")
и std::tstring
для Linux, а также для Windows.
3 - Должен быть улов!
И есть.
Во-первых, существует проблема загрязнения пространства имен std
с вашими префиксными символами t
, которые должны быть запрещены. Тогда не забудьте добавить макросы, которые будут загрязнять ваш код. В текущем случае, я думаю, это нормально.
Во-вторых, я предположил, что вы используете MSVC в Windows (таким образом, макрос _MSC_VER
) и GCC в Linux (таким образом, макрос __GNUC__
). Измените определения, если ваш случай отличается.
Три, ваш код должен быть нейтральным Unicode, т.е. вы не должны полагаться на свои строки как UTF-8 или UTF-16. На самом деле, ваш источник должен быть пустым из ничего, кроме символов ASCII, чтобы оставаться совместимым с кросс-платформой.
Это означает, что некоторые функции, такие как поиск присутствия ONE Unicode Glyph, должны выполняться с помощью отдельной части кода, которая будет иметь все #define
, необходимые для правильного выбора.
Например, поиск символа é
(Unicode Glyph 233) потребует от вас поиска первого символа 233 при использовании UTF-16 wchar_t в Windows и первой последовательности из двух символов 195 и 169 на UTF-8 char
. Это означает, что вы должны либо использовать некоторую библиотеку Unicode, либо сделать это самостоятельно.
Но это больше проблема самого Unicode, чем Unicode в Windows или Linux.
3.a - Но Windows не должна правильно обрабатывать UTF-16
Так что?
"Канонический" пример, который я видел описанным, - это элемент управления EDIT Win32, который, как предполагается, не сможет правильно отменить не-BMP UTF-16 char в Windows (не то, что я не проверял ошибку, я просто надел 't забота достаточно).
Это проблема Microsoft. Ничто из того, что вы решите в коде, не изменит тот факт, что эта ошибка существует или нет в Win32 API. Поэтому использование символов UTF-8 в Windows не будет исправлять ошибку в элементе управления EDIT. Единственное, что вы можете надеяться сделать, это создать свой собственный элемент управления EDIT (подклассы он и правильно обработать событие BACKSPACE?) Или ваши собственные функции преобразования.
Не смешивайте две разные проблемы, а именно: предполагаемая ошибка в API Windows и собственный код. Ничто в вашем собственном коде не позволит избежать ошибки в API Windows, если вы НЕ используете предполагаемый прослушиваемый Windows API.
3.b - Но UTF-16 в Windows, UTF-8 в Linux, не так уж сложно?
Да, это может привести к ошибкам на какой-либо платформе, которые не будут выполняться на других, если вы слишком много думаете о персонажах.
Я предположил, что вашей основной платформой была Windows (или вы хотели предоставить библиотеку для пользователей wchar_t
и char
).
Но если это не так, если Windows не является вашей основной платформой, то есть решение предполагать, что все ваши char и std::string будут содержать символы UTF-8, если не указано иное. Тогда вам понадобится обернуть API, чтобы убедиться, что ваша строка char UTF-8 не будет ошибочно принята за строку ANSI (или другую кодированную) char в Windows. Например, предполагается, что имена файлов для библиотек stdio.h
и iostream
будут кодироваться, а также версия ANSI версии Win32 API (например, CreateWindowA).
Это подход GTK +, который использует символы UTF-8, но не удивительно, что QT (на котором построен KDE Linux), который использует UTF-16.
Источник:
- QT: http://doc.qt.nokia.com/4.6/qstring.html#details
- GTK +: http://www.gtk.org/api/2.6/glib/glib-Character-Set-Conversion.html#filename-utf-8
Тем не менее, он не защитит вас от "Hey, но элементы управления Win32 не обрабатывают мои символы юникода!" проблема, поэтому вам все равно придется подклассифицировать этот элемент управления на желаемое поведение (если ошибка все еще существует)...
Приложение
Посмотрите мой ответ на std:: wstring VS std::string для полной разницы между std::string
и std::wstring
.