Как моя программа может переключиться с ASCII на Unicode?

Я хочу написать программу на C++, которая должна работать на Unix и Windows. Эта программа должна иметь возможность использовать как Unicode, так и не Unicode среды. Его поведение должно зависеть только от параметров среды.

одна из приятных функций, которые я хочу иметь, - это манипулировать именами файлов, считанными из каталогов. Это может быть unicode... или нет.

каков самый простой способ достичь этого?

6 ответов


я хочу написать программу на C++, который должен работать на Unix и Windows.

во-первых, убедитесь, что вы понимаете разницу между тем, как Unix поддерживает Unicode и как Windows поддерживает Unicode.

в дни до Unicode обе платформы были похожи в том, что каждая локаль имела свои предпочтительные кодировки символов. Строки были массивами char. Один char = один символ, за исключением нескольких восточноазиатских локалей, которые использовали двухбайтовый кодировки (которые были неудобны в обращении из-за не-самосинхронизирующийся).

но они подошли к Unicode двумя разными способами.

Windows NT принял Unicode в первые дни, когда Unicode должен был быть 16-разрядной кодировкой с фиксированной шириной. Microsoft написала совершенно новую версию Windows API, используя 16-разрядные символы (wchar_t) вместо 8-битного символа. Для обратной совместимости они сохранили старый API" ANSI " и определили тонну макросов таким образом, вы можете вызвать версию "ANSI" или "Unicode" в зависимости от того,.

в мире Unix (в частности, Plan 9 от Bell Labs) разработчики решили, что было бы проще расширить существующую поддержку многобайтовых символов Unix в Восточной Азии для обработки 3-байтовых символов, и создали кодировку, теперь известную как UTF-8. В последние годы Unix-подобные системы делают UTF-8 кодировкой по умолчанию для большинства локалей.

теоретически Windows мог бы расширьте их поддержку ANSI, чтобы включить UTF-8, но они до сих пор не, из-за жестко закодированных предположений о максимальном размере символа. Итак, в Windows вы застряли с API ОС, который не поддерживает UTF-8 и библиотеку времени выполнения C++, которая не поддерживает UTF-8.

в результате этого:

  • UTF-8-Самая простая кодировка для работы в Unix.
  • UTF-16 является самая простая кодировка для работы с Windows.

это создает столько же осложнений для кросс-платформенного кода,сколько и звучит. Это проще, если вы просто выберите одну кодировку Unicode и придерживайтесь его.

какая кодировка должна быть?

посмотреть UTF-8 или UTF-16 или UTF-32 или UCS-2

в итоге:

  • UTF-8 позволяет сохранить предположение о 8-битном коде единицы.
  • UTF-32 позволяет сохранить предположение о символах фиксированной ширины.
  • UTF-16 отстой, но это все еще вокруг из-за Windows и Java.

тип wchar_t

является стандартным типом c++ "широкий символ". Но это кодирование не стандартизировано: это UTF-16 на Windows и UTF-32 на Unix. Кроме тех платформ, которые используют зависит от локали wchar_t кодировки как наследие из Восточной Азии программирование.

если вы хотите использовать UTF-32, используйте uint32_t или эквивалентный typedef для хранения символов. Или использовать wchar_t Если __STDC_ISO_10646__ определена и uint32_t.

новый стандарт C++ будет иметь char16_t и char32_t, что, надеюсь, прояснит путаницу в том, как представлять UTF-16 и UTF-32.

в файле TCHAR

является Windows typedef для wchar_t (предполагается, что UTF-16), когда _UNICODE определена и char (предполагается ,что " ANSI") иначе. Он был разработан для борьбы с перегруженным API Windows, упомянутым выше.

на мое мнение, TCHAR хреново. Он сочетает в себе недостатки наличия платформы-зависимых char с недостатками платформы-зависимых wchar_t. Избегать его.

самое главное

кодировки символов - это обмен информацией. Это то, что означает" II " в ASCII. Ваша программа не существует в вакууме. Вы должны читать и писать файлы, которые с большей вероятностью будут закодированы в UTF-8, чем в UTF-16.

С другой стороны, вы можете работать с библиотеками, которые используют символы UTF-16 (или реже UTF-32). Это особенно верно для Windows.

моя рекомендация используйте форму кодирования, которая минимизирует количество преобразования, которое вам нужно сделать.

эта программа должна иметь возможность использовать оба: Unicode и non Юникод среда

было бы намного лучше, чтобы ваша программа работала полностью в Unicode внутренне и имела дело только с устаревшими кодировками для чтения устаревших данных (или записи их, но только если явно просят.)


вы должны решить,как вы представляете текст внутри.
Это должно быть постоянным независимо от того, что вы выберете.

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

UTF-8 отлично подходит для хранения и передачи при сжатии что ж.
Но мне не нравится это как внутреннее представление, поскольку оно имеет переменную длину.

UTF-16: должен был стать спасителем всего человечества.
Но был быстро superceeded на УТФ-32

UTF-32: исправлено. Поэтому отлично подходит для внутреннего представления и манипуляции.
Легко конвертировать в/из UTF-8.
Очень громоздкие (каждый символ занимает 4 байта).

большинство ОС уже преобразованы в строковое представление UTF или заголовок такой образ. Таким образом, использование формата onld obsolte внутри, например ISO-8859, просто означает, что вызовы ОС вызовут дополнительную работу, поскольку строка преобразуется в/из UTF. В результате это кажется пустой тратой времени (для меня).


вы должны решить, какую кодировку Unicode вы хотите использовать e.G UTF-8, ISO-8859-1 и т.д. Тогда вы должны учитывать это в своем C++ во всех ваших манипуляциях со строками. Е. Г. взгляните на w_char и wstring, которая. В среде, отличной от Unicode, я предполагаю, что вы имеете в виду, что входные переменные будут только ascii?


идентификатор локали "" (пустая строка) указывает локаль по умолчанию для конкретной реализации. Итак, если вы установите глобальную локаль в std::locale("") затем вы теоретически получите локаль по умолчанию, которая инициализируется на основе настроек локали среды. Это примерно как стандарт C++ дает вам.

Это имеет некоторые основные ограничения на Windows, где MSVC не proivde любой std:: locale с кодировкой UTF-8. И Mac OS X не предоставляет никаких std:: locale other чем языка "C" локали.

на практике обычно стандартизировать на UTF-8 закодированный std:: string везде внутри вашего приложения. Тогда в тех конкретные случаи, когда вам нужно взаимодействовать с ОС, сделать преобразование кода по мере необходимости. Например, вы будете использовать const char*, закодированный с UTF-8, чтобы определить имя файла в unix, но wchar*, закодированный с UTF-16, чтобы определить имя файла в windows.

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


лично я бы пошел другим путем.

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

определенная кодировка предназначена для легкой связи, однако, поскольку Unix по умолчанию использует UTF-8, а Windows-UTF-16, невозможно иметь универсальную кодировку. Поэтому я бы просто предложил использовать ваше собственное внутреннее представление и применить подходящий преобразование в зависимости от целевой ОС. Это происходит с помощью общего интерфейса для функций, которые вам нужны, и реализации per OS/encoding.

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

в итоге:

  • ICU is великий
  • если вы реализуете его самостоятельно и хотите быть несколько "стандартными", используйте UTF-32 (4 байта на точку)
  • если вы плотно в памяти, 21 бит (

преобразование может показаться "компьютерным", но:

  • вы можете сделать это поточном
  • это намного быстрее, чем I / O

мои 2 cts, как говорится:)


лучший способ, который я видел, это иметь typedefs и очень мало макросов, определенных на основе условной компиляции. Например:

#ifdef UNICODE
#define mychar wchar_t
#define s(a) L ## a
typedef std::wstring mystringa;
#else
#define mychar char
#define s(a) a
typedef std::string mystringa;
#endif
typedef std::basic_string<mychar> mystringb;

и так далее. Затем вы будете использовать строки как s("foo") и mystringa(s("foo"));. Я показал два способа создания строкового типа. Либо должен работать.