Кросс-платформенный С++: использовать собственную кодировку строк или стандартизировать все платформы?

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

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

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

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

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

Ответ 1

и UTF-8 в linux.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Полностью совместим с ASCII. Любая строка ASCII является допустимой строкой UTF-8.
  • Библиотека std отлично работает с строками UTF-8. (*)
  • Библиотека С++ std отлично работает с UTF-8 (std::string и друзьями). (*)
  • Legacy-код отлично работает с UTF-8.
  • Достаточно любая платформа поддерживает UTF-8.
  • Отладка намного проще с UTF-8 (поскольку она совместима с ASCII).
  • Без малого-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 char). Проблема с wchar_t заключается в том, что с ней нет кодировки. Это просто абстрактный широкоформатный char, который больше обычного char (16 бит в Windows, 32 бит на большинстве * nix).

Ответ 2

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

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

Ответ 3

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

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

Ответ 5

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

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

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

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

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