Кроссплатформенный C ++: использовать встроенную кодировку строк или стандартизировать на разных платформах? - PullRequest
10 голосов
/ 02 апреля 2012

Мы внимательно следим за разработкой Windows и Linux и разработали два разных подхода, которые, похоже, имеют свои достоинства.Естественный тип строки Unicode в Windows - UTF-16 и UTF-8 в Linux.

Мы не можем решить, является ли наилучший подход:

  1. Стандартизировать по одной из двух во всей логике нашего приложения (и постоянных данных) и сделать другие платформывыполните соответствующие преобразования

  2. Используйте естественный формат для ОС для логики приложения (и, следовательно, для вызовов в ОС) и выполняйте преобразование только в точке IPC и постоянства.

Мне кажется, они оба примерно так же хороши, как друг друга.

Ответы [ 5 ]

6 голосов
/ 24 августа 2012

и UTF-8 в Linux.

Это в основном верно для современного Linux.На самом деле кодировка зависит от того, какой API или библиотека используется.Некоторые жестко запрограммированы на использование UTF-8.Но некоторые читают переменные окружения LC_ALL, LC_CTYPE или LANG для определения используемой кодировки (например, библиотеки Qt).Так что будьте осторожны.

Мы не можем решить, будет ли лучший подход

Как обычно, это зависит.

Если 90% кода будет иметь делосо специфичным для платформы API конкретным способом, очевидно, лучше использовать специфичные для платформы строки.В качестве примера - драйвер устройства или собственное приложение iOS.

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

Во втором случае у вас есть выбор:

  • Использовать кроссплатформенную библиотеку, которая обеспечивает поддержку строк (например, Qt, ICU)
  • Используйте голые указатели (я считаю, что std :: string также «голым указателем»)

Если работа со строками является важной частью вашего приложения, выбор хорошей библиотеки для строкхороший ход.Например, Qt имеет очень солидный набор классов, который покрывает 99% общих задач.К сожалению, у меня нет опыта работы с ICU, но он также выглядит очень хорошо.

При использовании некоторой библиотеки для строк вам нужно заботиться о кодировании только при работе с внешними библиотеками, API платформы или отправке строк по сети (илидиск).Например, многие программисты на Cocoa, C # или Qt (у всех есть поддержка сплошных строк) очень мало знают о деталях кодирования (и это хорошо, поскольку они могут сосредоточиться на своей основной задаче).

Мой опыт вработа со строками - немного , поэтому я лично предпочитаю голые указатели.Код, который их использует, очень переносим (в том смысле, что его можно легко использовать в других проектах и ​​платформах), поскольку имеет меньше внешних зависимостей.Это также очень просто и быстро (но, чтобы почувствовать это, вероятно, понадобится некоторый опыт и опыт работы с Unicode).

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

  • Вы работаете со всеми строками, а разделение, поиск, сравнение - редкая задача
  • Вы можете использовать одинаковую кодировку во всех компонентах и ​​нуждаетесь в преобразовании только при использованииAPI платформы
  • Все ваши поддерживаемые платформы имеют API для:
    • Преобразования из вашей кодировки в ту, которая используется в API
    • Преобразование из кодировки API в ту, которая используется в вашем коде
  • Указатели не являются проблемой в вашей команде

Из моего небольшого конкретного опыта это на самом деле очень распространенный случай.

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

С моей точки зрения, UTF-8 является абсолютным победителем.Если вы не можете использовать UTF-8 - используйте библиотеку строк или API платформы для строк - это сэкономит вам много времени.

Преимущества UTF-8:

  • ПолностьюСовместим с ASCII.Любая строка ASCII является допустимой строкой UTF-8.
  • Библиотека C std прекрасно работает со строками UTF-8.(*)
  • Библиотека C ++ std прекрасно работает с UTF-8 (std :: string и friends).(*)
  • Устаревший код прекрасно работает с UTF-8.
  • Практически любая платформа поддерживает UTF-8.
  • Отладка НАМНОГО проще с UTF-8 (так какСовместим с ASCII).
  • Нет беспорядка Little-Endian / Big-Endian.
  • Вы не заметите классическую ошибку "О, UTF-16 не всегда 2 байта?".

(*) До тех пор, пока вам не понадобится их лексическое сравнение, преобразуйте регистр (toUpper / toLower), измените форму нормализации или что-то в этом роде - если вы это сделаете - используйте библиотеку строк или API платформы.

Недостаток сомнителен:

  • Менее компактен для китайского языка (и других символов с большими номерами кодовых точек), чем UTF-16.
  • Труднее (немного на самом деле) перебирать символы.

Итак, я рекомендую использовать UTF-8 в качестве обычной кодировки для проектов, которые не используют библиотеку строк.

Но кодирование - не единственный вопрос, на который вам нужно ответить.

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

Например, если пароль пользователя содержит «йёжиг», он будет представлен по-разному (как в UTF-8, так и в UTF-16) при вводе на Mac (который в основном использует форму нормализации D) и в Windows (которая больше всего любит форму нормализации C ). Поэтому, если пользователь, зарегистрированный под Windows с таким паролем, будет проблематично войти в систему под Mac.

Кроме того, я бы не рекомендовал использовать wchar_t (или использовать его только в коде Windows как тип символов UCS-2 / UTF-16). Проблема с wchar_t заключается в том, что с ним нет кодировки. Это просто абстрактный широкий символ, который больше нормального символа (16 бит в Windows, 32 бита в большинстве * nix).

0 голосов
/ 12 сентября 2012

Это, кажется, довольно поучительно по теме.http://www.utf8everywhere.org/

0 голосов
/ 06 июня 2012

Программирование с использованием UTF-8 затруднено, так как длины и смещения смешаны.Например,

    std::string s = Something();
    std::cout << s.substr(0, 4);

не обязательно находит первые 4 символа.

Я бы использовал все, что есть wchar_t.На Windows это будет UTF-16.На некоторых платформах * nix это может быть UTF-32.

При сохранении в файл я бы рекомендовал преобразовать в UTF-8.Это часто делает файл меньше и удаляет все зависимости от платформы из-за различий в sizeof(wchar_t) или в порядке следования байтов.

0 голосов
/ 06 июня 2012

C ++ 11 предоставляет новые типы строк u16string и u32string.В зависимости от поддержки, которую предоставляют версии вашего компилятора, и ожидаемой продолжительности жизни, может быть целесообразно поддерживать прямую совместимость с ними.

Кроме этого, использование библиотеки ICU , вероятно,Ваш лучший шанс на кроссплатформенную совместимость.

0 голосов
/ 02 апреля 2012

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

Я бы использовал юникод (utf-16), потому что он проще обрабатывать внутри и должен работать лучше из-за постоянной длины для каждого символа.UTF-8 идеально подходит для вывода и хранения, потому что он обратно совместим с латинским ascii и использует только 8 бит для английских символов.Но внутри программы 16-битная проще в обращении.

...