我使用libiconv
将我的char数组转换为UTF-16字符串。我有疑问。
iconv
函数的签名
size_t iconv(iconv_t cd,
const char* * inbuf, size_t *inbytesleft,
char* * outbuf, size_t *outbytesleft);
这意味着,char
用于保存转换为的任何类型的字符(char vs wide char)。
我在学校的C老师告诉我,对于奇数或不可读的角色,我们应该使用wchar_t。我现在很困惑。
我在input = "KOTEX"
作为ASCII
编码类型测试了此方法,并希望输出另一个双倍长度的字符串,编码为UTF-16
。它立刻失败了。但是,如果我将目标代码页更改为UTF-8
,它将起作用,但返回的数据将丢失。那是为什么?
答案 0 :(得分:1)
iconv
的缓冲区参数实际上是char *
,但这并不意味着它们实际上代表C字符串。 (如果界面使用uint8_t*
代替,可能不那么令人困惑,但那是非常慢的; iconv
在stdint.h
之前就已经存在了)
Posix标准(以及Linux联机帮助页)试图明确这一点:
inbuf
和outbuf
,char **
的类型并不意味着指向的对象被解释为以null结尾的C字符串或字符数组。表示给定字符集编码方案中的字符的字节序列的任何解释都是在代码集转换器内部完成的。 (Posix.2008
因此,如果您计划转换为UTF-16,则应为UTF-16提供具有适当数据类型的输出缓冲区。 wchar_t
不是适当的数据类型;在很多系统上,它会太大了。 uint16_t
没问题。
请注意,实际上有三种不同的UTF-16编码(名称取决于系统;此处的名称由Gnu iconv
识别):
UTF16LE
(或UTF-16LE
):" Little endian" UTF-16。在这种格式中,首先是每个字符的低位字节,然后是高位字节。 KOTEX
是
{0x4B, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x45, 0x00, 0x58, 0x00}
UTF16BE
(或UTF-16BE
):" Big endian" UTF-16。在这种格式中,首先是每个字符的高位字节,然后是低位字节。 KOTEX
是:
{0x00, 0x4B, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x45, 0x00, 0x58}
UTF16
(或UTF-16
):UTF16BE
或UTF16LE
,具体取决于该机器是big-endian还是little-endian;转换后的字符串以Byte Order Mark (BOM)开头。在小端机器(我的)上,KOTEX
是
{0xFF, 0xFE, 0x4B, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x45, 0x00, 0x58, 0x00}
在大端机器上,它将是:
{0xFE, 0xFF, 0x00, 0x4B, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x45, 0x00, 0x58}
UTF16
(带有endian规范的未加工)始终以BOM开头这一事实意味着您必须记住在输出缓冲区中提供额外的(2字节)字符。否则,您最终会得到E2BIG
。
在所有这三种编码中,basic multilingual plane (BMP)之外的字符需要两个(两个字节)字符位置,即所谓的surrogate pair。所有ascii字符都在BMP上,所以你不需要为ascii-to-utf16转换担心这个问题,但如果你正在使用utf8-to-utf16,你就会这么做。