Кросс-платформенные строки (и Unicode) в С++
Итак, я наконец вернулся к своей основной задаче - портировал довольно большой проект на С++ из Windows в Mac.
Сразу же я попал в проблему, когда wchar_t - 16 бит в Windows, но 32-бит на Mac. Это проблема, потому что все строки представлены wchar_t, и будут выполняться строковые данные между машинами Windows и Mac (как в виде данных на диске, так и в виде сетевых данных). Из-за того, как он работает, было бы не совсем просто преобразовать строки в какой-то общий формат перед отправкой и получением данных.
В последнее время мы действительно начали поддерживать гораздо больше языков, поэтому мы начинаем работать с множеством данных Unicode (а также с языками справа налево).
Теперь я мог бы объединить несколько идей здесь и вызвать больше проблем для себя, чем нужно, поэтому я задаю этот вопрос. Мы думаем, что сохранение всех наших данных в памяти, как UTF-8, имеет большой смысл. Это решает проблему wchar_t с разными размерами, это означает, что мы можем легко поддерживать несколько языков, а также значительно уменьшать наш объем памяти (у нас есть большая часть - в основном, на английском языке) - но это не похоже на то, что многие люди делают это. Что-то нам не хватает? Там очевидная проблема, с которой вам приходится иметь дело, где длина строки может быть меньше размера памяти, хранящей эти строковые данные.
Или использует UTF-16 лучше? Или мы должны придерживаться wchar_t и писать код для преобразования между wchar_t и, скажем, Unicode в местах, где мы читаем/записываем на диск или в сеть?
Я понимаю, что это опасно близко к запросам мнений - но мы нервничаем, что упускаем из виду что-то очевидное, потому что не похоже, что есть много классов строк Unicode (например) - но все же есть много кода для преобразования в/из Юникода, например, в boost:: locale, iconv, utf-cpp и ICU.
Ответы
Ответ 1
Всегда используйте протокол, определенный для байта, когда используется файл или сетевое соединение. Не полагайтесь на то, как компилятор С++ хранит что-либо в памяти. Для текста в Юникоде это означает выбор как кодировки, так и порядка байтов (хорошо, UTF-8 не заботится о порядке байтов). Даже если платформы, которые вы в настоящее время хотите поддерживать, имеют аналогичную архитектуру, вероятно, придет другая популярная платформа с различным поведением или даже новая ОС для одной из ваших существующих платформ, и вы будете рады, что напишете переносимый код.
Ответ 2
Как правило: UTF-16 для обработки, UTF-8 для связи и хранения.
Конечно, любое правило может быть нарушено, и этот камень не высечен.
Но вы должны знать, когда это нормально, чтобы сломать его.
Например, может быть хорошей идеей использовать что-то еще, если используемая вами среда хочет чего-то другого. Но API-интерфейсы Mac OS X используют UTF-16, как и Windows. Таким образом, UTF-16 имеет больше смысла.
Сложнее преобразовать, прежде чем вы ставите/получаете вещи в сети (потому что вы, вероятно, делаете это в 2-3 процедурах), чем все конверсии для вызова API OS.
Также важно, какой тип приложения вы разрабатываете.
Если это что-то с очень маленькой текстовой обработкой и очень мало звонков в систему (что-то вроде сервера электронной почты, который в основном перемещает вещи без их изменения), то UTF-8 может быть хорошим выбором.
Итак, насколько вы можете ненавидеть этот ответ, "это зависит".
Ответ 3
Я использую UTF-8 как внутреннее представление. Вы просто теряете проверку длины строки, и в любом случае это не очень полезно. Для преобразования Windows API я использую свои собственные функции преобразования Win32 которые я придумал здесь. Поскольку Mac и Linux (по большей части, стандартный UTF-8, не нуждаются в том, чтобы конвертировать что-либо там). Бесплатные бонусы:
- использовать простой старый
std::string
.
- байтовый сетевой/потоковый транспорт.
- Для большинства языков замечательный объем памяти.
- Для большей функциональности: utf8cpp
Ответ 4
ICU имеет строковый класс С++, UnicodeString