Как лучше всего справиться с 16-битным безобразием wchar_t в Windows? - PullRequest
2 голосов
/ 12 июля 2010

Я пишу слой-обертку для использования с mingw, который предоставляет приложению виртуальную среду UTF-8.Функции, которые имеют дело с именами файлов, являются обертками, которые конвертируют из UTF-8 и вызывают соответствующие функции "_w" и так далее.Большая проблема, с которой я столкнулся, заключается в том, что Windows wchar_t является 16-битной.

Для операций с файловой системой это не имеет большого значения.Я могу просто конвертировать туда и обратно между UTF-8 и UTF-16, и все будет работать.Но стандартный API преобразования многобайтовых / широких символов в C не допускает использование символов multi-wchar_t.

Возможные решения:

  1. Обеспечение среды CESU-8 вместо UTF-8.Мне действительно не нравится этот.
  2. Выбери легкий путь и поддержи только BMP.Считайте недействительными последовательности UTF-8 длиной 4.
  3. Расширение оболочки для замены mingw wchar_t на typedef int32_t wchar_t; и взаимодействие с WCHAR и wchar_t различными.Это боль, но она может быть идеальной для портирования приложений, которые ожидают чистой среды типа POSIX и не используют wchar_t для каких-либо целей Windows-API.
  4. Следующий взлом:

mbrtowc выводит wchar_t, соответствующий старшему суррогату после чтения первых 3 байтов 4-байтового символа UTF-8, и сохраняет оставшееся состояние в объекте mbstate_t.Получив следующий байт, он объединяет его с сохраненным состоянием для вывода низкого суррогата.Если последний байт оказывается недействительным, он возвращает -1 (с EILSEQ) и одиночный суррогат заканчивается в выходном потоке (плохой ...).

wcrtomb выводит первые 2 байта UTF-8, когда он обрабатывает верхний суррогат и сохраняет оставшееся состояние в своем mbstate_t объекте.Когда он впоследствии обрабатывает низкий суррогат, он комбинирует это с сохраненным состоянием, чтобы вывести последние 2 байта UTF-8.Если действительный низкий суррогат не получен, он возвращает -1 (с EILSEQ) и неполная последовательность UTF-8 заканчивается в выходном потоке (плохой ...).

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

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

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

Ответы [ 2 ]

1 голос
/ 13 июля 2010

Я бы сделал что-то вроде # 4, но не генерирую никаких выходных данных, пока вы не убедитесь, что они верны.

  • mbrtowc должен декодировать весь символ.Если он находится за пределами BMP, выведите старший суррогат и сохраните низкий суррогат в mbstate_t.
  • wcrtomb должен хранить старшие суррогаты в mbstate_t, затем выведите все 4 байта UTF-8, еслисимвол действителен.
0 голосов
/ 12 июля 2010

Если вы работаете в Windows, вы конвертируете между UTF-16 и UTF-8 целую строку за раз, используя MultiByteToWideChar и WideCharToMultiByte.

Хотя режимом по умолчанию в GCC является 32-битный wchar_t, существуют переключатели компиляции, которые меняют это, и в более общем случае спецификации c & c ++ не определяют размер wchar_t - на самом деле wchar_t может быть такого же размера, как char.

Если вы хотите избежать использования API-интерфейсов Windows (в коде оболочки Windows !?), используйте mbstowcs для преобразования всей строки за раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...