Я пишу слой обертки для использования с mingw, который обеспечивает приложение виртуальной средой UTF-8. Функции, которые имеют дело с именами файлов, - это обертки, которые конвертируют из UTF-8 и вызывают соответствующие функции «_w» и т. Д. Большая проблема, с которой я столкнулся, заключается в том, что Windows wchar_t
- это 16-разрядная версия.Как лучше всего справляться с 16-битным wchar_t Windows?
Для операций с файловой системой это не имеет большого значения. Я могу просто конвертировать туда и обратно между UTF-8 и UTF-16, и все будет работать. Но стандартный API-интерфейс преобразования многобайтовых/широкоформатных символов не позволяет использовать символы multi-wchar_t.
Возможные решения:
- Обеспечить среду CESU-8 вместо UTF-8. Мне это действительно не нравится.
- Простой выход и поддержка только BMP. Обработать последовательности UTF-8 длиной 4 как недействительные.
- Расширение обертки для замены mingw's
wchar_t
сtypedef int32_t wchar_t;
и дело сWCHAR
иwchar_t
отличается. Это боль, но это может быть идеальным для переноса приложений, ожидающих чистой среды типа POSIX, и не использоватьwchar_t
для любых целей Windows-API. - Ниже обходной:
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 и, следовательно, к любому возможному имени файла/аргументу/etc. текст, с которым может потребоваться приложение.
Недостатки в том, что он строго не соответствует строкам ISO C (wchar_t
), и что он задерживает обнаружение некорректных символов до тех пор, пока не будет записан неправильный частичный вывод.
Я ищу информацию о различных вариантах, и особенно о предлагаемом вами взломе: разумно ли, могут ли противники вызвать серьезные ошибки, и есть ли какие-либо другие недостатки, которые я еще не рассматривал, чтобы система полностью работала. Я также был бы рад услышать любые другие возможные решения, о которых я не думал.
Звучит неплохо, но я не уверен, что это возможно. Если 'mbrtowc' хранит низкий суррогат в' mbstate_t', тогда ему придется выводить 'wchar_t' на следующий вызов, не потребляя никакого ввода. Но возвращаемое значение 0 зарезервировано для преобразования нулевого байта/конца строки. Я предполагаю, что он мог бы потреблять дополнительный байт от следующего символа, но если это был однобайтовый символ, странная буферизация продолжилась. Как вы думаете? –
Это сложно, потому что стандарт C предполагает, что 'wchar_t' может представлять любой символ, и Microsoft нарушила его. Я не думаю, что можно написать соответствующий «mbrtowc» с UTF-16. – dan04
Возвращаемое значение 0 не может быть проблемой, если вызывающий код проверяет значение 'wch' вместо предположения U + 0000 на основе возвращаемого значения. Я сам не использую 'mbrtowc' (вместо этого встроенная функция преобразования, которая работает на целые строки), поэтому я не уверен, какая проблема будет на практике. – dan04