4

我正在编写一个与 mingw 一起使用的包装层,它为应用程序提供虚拟 UTF-8 环境。处理文件名的函数是从 UTF-8 转换并调用相应的“_w”函数的包装器,依此类推。我遇到的最大问题是 Windowswchar_t是 16 位的。

对于文件系统操作,这没什么大不了的。我可以在 UTF-8 和 UTF-16 之间来回转换,一切正常。但是标准的 C 多字节/宽字符转换 API 不允许多 wchar_t 字符。

可能的解决方案:

  1. 提供 CESU-8 环境而不是 UTF-8。我真的不喜欢这个。
  2. 采取简单的方法,只支持 BMP。将长度为 4 的 UTF-8 序列视为无效。
  3. 扩展包装以替换 mingw'swchar_ttypedef int32_t wchar_t;处理WCHARwchar_t不同。这很痛苦,但它可能是移植需要干净 POSIX 类型环境且不wchar_t用于任何 Windows-API 目的的应用程序的理想选择。
  4. 以下黑客:

mbrtowcwchar_t读取一个 4 字节 UTF-8 字符的前 3 个字节后,输出对应于高代理的 a,并将剩余状态保留在mbstate_t对象中。在接收到下一个字节后,它将其与保存的状态结合以输出低代理。如果最后一个字节最终无效,则返回 -1(使用 EILSEQ),并且在输出流中会出现一个单独的代理项(坏...)。

wcrtomb在处理高位代理时输出 UTF-8 的前 2 个字节,并将剩余状态保存在其mbstate_t对象中。当它随后处理低代理时,它将其与保存的状态相结合以输出 UTF-8 的最后 2 个字节。如果未接收到有效的低代理,则返回 -1(使用 EILSEQ),并且输出流中会出现不完整的 UTF-8 序列(坏...)。

这个 hack 的好处是只要输入有效,它就可以工作,并允许访问任何 UTF-8 字符,从而访问任何可能的文件名/参数/等。应用程序可能需要使用的文本。

缺点是它不严格符合 ISO C(wchar_t字符串不允许有状态),并且它延迟了对畸形字符的检测,直到已经写入了不正确的部分输出。

我正在寻找有关不同选项的反馈,尤其是我提出的 hack:它是否合理,缺点是否可能导致严重错误,以及是否还有其他我尚未考虑的缺点可能会阻止该计划完全工作。我也很高兴听到我没有想到的任何其他可能的解决方案。

4

2 回答 2

2

我会做类似 #4 的事情,但在确定输入有效之前不要生成任何输出。

  • mbrtowc应该解码整个字符。如果它在 BMP 之外,则输出高代理并将低代理存储在mbstate_t.
  • wcrtomb应该在 中存储高代理mbstate_t,然后如果字符有效则输出所有 4 个 UTF-8 字节。
于 2010-07-13T06:20:23.310 回答
0

如果您在 Windows 上,您可以使用 MultiByteToWideChar 和 WideCharToMultiByte 一次在 UTF-16 和 UTF-8 之间转换整个字符串。

虽然 GCC 中的默认模式是 32 位 wchar_t,但有一些编译开关可以改变这一点,而且更一般地说,c & c++ 规范没有指定 wchar_t 的大小——实际上 wchar_t 可以与 char 大小相同。

如果您想避免使用 Windows API(在您的 Windows 包装代码中!?)然后使用 mbstowcs 一次转换整个字符串。

于 2010-07-12T13:30:23.770 回答