Как лучше всего создавать библиотеки, поддерживающие Unicode и ASCII в C ++?

Я работаю над написанием некоторых библиотек, которые будут использоваться как внутри компании, так и клиентами, и мне было интересно, какой лучший способ поддержки Unicode и ASCII. Похоже, что Microsoft (в библиотеках MFC) записывает классы Unicode и ASCII и делает что-то подобное в файлах заголовков, используя макросы:

#ifdef _UNICODE
#define CString CStringW
#else
#define CString CStringA
#endif

Хотя я не большой поклонник макросов, он выполняет свою работу. Если я пишу библиотеки с использованием STL, имеет ли смысл писать заголовки, содержащие такие вещи:

#ifdef _UNICODE
#define GetLastErrorString GetLastErrorStringW
#else
#define GetLastErrorString GetLastErrorStringA
#endif

std::string GetLastErrorStringA();
std::wstring GetLastErrorStringW();

Или мне просто выпустить отдельные библиотеки, одну для ASCII и одну для Unicode?

Просто интересно, что люди думают о лучшем поступке в этой ситуации.

ОБНОВЛЕНИЕ: рассмотрение некоторых комментариев и вопросов:

  • Это будут библиотеки классов C ++.
  • Я считаю, что мне нужно будет использовать кодировку UTF-16, поскольку я хотел бы поддерживать азиатские наборы символов.
  • У меня две причины для внедрения Unicode: 1) Все новые SDK поддерживают Unicode, и я не уверен, что будущие SDK или сторонние библиотеки будут поддерживать отдельные версии ASCII в будущем. 2) Хотя мы не будем полностью интернационализировать наше приложение, было бы неплохо, если бы мы могли обрабатывать ввод данных пользователем (например, имена) и загрузку файлов по путям, содержащим азиатские символы.

person bsruth    schedule 30.09.2009    source источник
comment
Вы разрабатываете плоский API в стиле C или набор классов C ++?   -  person Michael    schedule 30.09.2009
comment
В вашем примере есть проблема: вам также необходимо указать псевдоним возвращаемого типа метода, если вы хотите иметь шанс, что он компилирует не сам метод (хотя вам, возможно, придется использовать #define в реализации метода) .   -  person Matthieu M.    schedule 30.09.2009
comment
По моему опыту, вам не нужно использовать UTF-16 для азиатских (CJK) символов. Моя программа отлично справляется с ними с многобайтовым UTF-8 без какого-либо колдовства.   -  person akaltar    schedule 07.07.2013


Ответы (4)


Я бы сделал внутреннюю библиотеку полностью Unicode. Тогда для ASCII будет существовать набор классов адаптеров C ++, которые будут преобразованы в реализацию Unicode.

person Michael    schedule 30.09.2009
comment
Возникает вопрос: необходимо ли внутреннее использовать Unicode, поскольку в зависимости от кодировки простой std :: string может помочь. - person Matthieu M.; 30.09.2009

Вы можете хранить строки Unicode в std :: string, если сначала конвертируете их в UTF-8.

Вам нужна только wstring при взаимодействии с вызовами UTF-16, такими как Windows API. В этом случае вы можете преобразовать свои строки в wstrings локально, где это необходимо. Это может быть немного обременительно, но не так уж и плохо.

person StackedCrooked    schedule 30.09.2009

Вопрос немного неточный, но ...

Сначала вам нужно уточнить кодировку. Юникод - это просто представление символов (каждый из которых связан с кодовой точкой), когда дело доходит до работы с Юникодом в приложении, вы должны выбрать, как будут представлены кодовые точки. Если вы можете использовать Utf-8, вам не придется беспокоиться о широких символах, вы можете хранить данные в простом std :: string :)

Затем вам нужно уточнить свою проблему:

  • вы хотите поддерживать записи в Unicode и Ascii?
  • или ты про вывод?
  • есть ли способ, которым вы могли бы использовать std :: locale, чтобы узнать, в какой кодировке вы должны выводить?

Я работаю над интернационализированным приложением (веб-сайт с бэкэндом C ++ ...), и мы просто используем std :: string внутри. Вывод в Ascii или Utf-8 зависит от файла перевода, но представление данных не меняется ни на йоту (за исключением подсчета символов, см. мой пост по этой теме).

На самом деле, я определенно не поклонник макросов, поскольку utf-8 должен был быть совместим с Ascii, если вы можете выбрать свою собственную кодировку, вы спасены!

person Matthieu M.    schedule 30.09.2009

Я t-h-i-n-k, вы спрашиваете о "понятности" кода, а не об использовании символов ASCII, UTF-8, 16 или 32 бит.

Если это так, я предпочитаю делать блоки кода как можно больше: это позволит использовать «вентиль» (символьную константу _UNICODE) для выбора либо отдельных файлов, либо, по крайней мере, больших фрагментов кода. Код, который меняет свое место через каждую вторую строку или около того, или, упаси небеса, внутри оператора, трудно понять.

Я бы посоветовал не использовать ворота для выбора включений отдельных файлов

#ifdef _UNICODE
#include "myUniLib.h"
#else
#include "myASCIILib.h"
#endif

как таковой повлечет за собой два, а может быть, даже три файла (файл Unicode, файл 646US (ASCII) и, возможно, ваш файл нексуса с приведенным выше кодом). Это в три раза больше вероятности того, что что-то будет потеряно и, как следствие, сбой сборки.

Вместо этого используйте шлюз в файле, чтобы выбрать большие блоки кода:

#ifdef _UNICODE
   ...lotsa code...
#else
   ...lotsa code...
#endif

Хорошо, допустим, вы делаете обратное: задаетесь вопросом о char против char (UTF-8) против W против A. Насколько универсальным вы хотите быть? CStrings, которые вы упомянули, предназначены только для мира Windows. Если вы хотите быть совместимыми с Mac и UNIX (ОК, Linux), вас ждут тяжелые испытания.

Кстати, ASCII ... больше не ... признанный стандарт. Есть ASCII и есть ... ASCII. Если вы имеете в виду семибитный «стандарт» из старых времен UNIX, то ближайшим, что я нашел, является ISO-646US. Эквивалент Unicode - ISO-10646.

Некоторым людям повезло с кодированием символов как URL-адресов: только буквы и цифры ASCII и знак процента. Хотя вам все время нужно кодировать и декодировать, хранилище действительно предсказуемо. Немного странно, да, но определенно новаторски.

Есть некоторые лингвистические подводные камни. Например, не зависит от регистра, чтобы он был двунаправленным (здесь я не знаю правильного слова). В немецком языке нижний регистр ß становится SS при переводе в верхний регистр. SS, однако, в нижнем регистре трансформируется в ss, а не в ß. В турецком есть нечто похожее. При разработке приложения не думайте, что переводы регистров могут вам помочь.

Также помните, что грамматический порядок в разных языках различается. Простое «Привет, Джим! Как у тебя понедельник?» может закончиться "Привет! Ваш, понедельник, все идет хорошо, Джим?"

Наконец, предупреждение: избегайте потокового ввода-вывода (std :: cin ‹< и std :: cout >>). Это заставляет вас встраивать генераторы сообщений таким образом, что их локализация становится очень сложной.

Вы задаете правильные вопросы. Впереди вас ждёт приключение! Лучший!

person Community    schedule 30.09.2009