(Untitled)

我在MSYS2下做了测试。Emoji字符📁需要2个wchar_t,需要4个char。Emoji字符✏️则需要2个wchar_t,需要6个char

Emoji Platform wchar_t char Display mbrtowc pwccheck
📁 MSYS2 2 4 3→1
✏️ MSYS2 2 6 ✔️ 3→1 ✔️
MSYS2 1 3 ✔️ 3→1 ✔️
📁 CentOS 1 4 ✔️ 4→1 ✔️
✏️ CentOS 2 6 ✔️ 3→1 ✔️
CentOS 1 3 ✔️ 3→1 ✔️

我们将这个表格归纳一下,由于转换过程是从小到大逐步尝试的,于是我们会遇到这个情况:将一个3字符长度的字符串尝试转换为一个宽字符后,它位于了代理项代码点(surrogate code point),是一个代理项代码单元。

这里有几个概念需要介绍一下(回答来自必应AI)。

A surrogate code point is a Unicode code point in the range U+D800…U+DFFF1. It is reserved for use by UTF-16, where a pair of surrogate code units (a high surrogate followed by a low surrogate) “stand in” for a supplementary character21.

一个代理项代码点是在范围 U+D800…U+DFFF1 的 Unicode 代码点。它被 UTF-16 保留,用于一对代理项代码单元(一个高代理项后跟一个低代理项)来“代替”一个补充字符。

一个例子是,Unicode 代码点 U+1F339(🌹)是一个补充字符,它在 UTF-16 中被编码为两个代理项代码单元:0xD83C(高代理项)和 0xDF39(低代理项)。

🌹 用 UTF-8 表示是 0xF0 0x9F 0x8C 0xB91。UTF-8 是一种变长字符编码,被定义为将码点编码为 1 至 4 个字节,具体取决于码点数值中有效二进制位的数量。

Unicode 的补充字符是指分配了 U+10000 到 U+10FFFF1 的 Unicode 代码点。在 UTF-8 中,这些字符都是 4 个字节长的1。所以,没有长度大于 4 的 Unicode 补充字符。

代理项代码单元与补充字符的关系是这样的:补充字符是指位于基本多文种平面(BMP)之外的字符,而代理项是 UTF-16 代码值1。在 UTF-16 中,需要一对代理项(一个高代理项和一个低代理项)来表示一个补充字符12。高代理项的范围是 U+D800 到 U+DBFF,低代理项的范围是 U+DC00 到 U+DFFF13。

所以这里有一个问题,mbrtowc函数转换了一个Unicode补充字符的前三个字符串,得到了一个宽字符串,是这个补充字符代理项对的前导代码单元,导致还剩下的一个字符肯定无法转换为正确的数据了。

根据必应提供的背景知识,补充字符一定是4个字符组成的。因此此处应该将4个字符一起处理,将其转换为2个宽字符。

这或许是mbrtowc在MSYS2下的问题,可能是因为Windows下的wchar_t的长度是2。
由于转换过程是4个字符串转换为2个宽字符串,故我们需要使用mbstowcs系列函数。