char 类型并将 ASCII 文本重新编码为 UTF-16
Posted
技术标签:
【中文标题】char 类型并将 ASCII 文本重新编码为 UTF-16【英文标题】:char type and re-encoding ASCII text into UTF-16 【发布时间】:2015-02-03 04:17:25 【问题描述】:我正在使用libiconv
将我的 char 数组转换为 UTF-16 字符串。我有疑问。
iconv
函数的签名
size_t iconv(iconv_t cd,
const char* * inbuf, size_t *inbytesleft,
char* * outbuf, size_t *outbytesleft);
这意味着,char
用于保存要转换为的任何类型的字符(字符与宽字符)。
我在学校的 C 老师教我,对于奇怪或不可读的字符,我们应该使用 wchar_t。我现在很困惑。
我在input = "KOTEX"
上以ASCII
编码类型测试此方法,并希望输出另一个编码为UTF-16
的双倍长度字符串。它立即失败。但是如果我将目标代码页更改为UTF-8
,它会起作用,但返回的数据会丢失。这是为什么呢?
【问题讨论】:
看看这是否有帮助gnu.org/software/libc/manual/html_node/iconv-Examples.html 【参考方案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
):“小端”UTF-16。在这种格式中,每个字符的低位字节在前,然后是高位字节。 KOTEX
是
0x4B, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x45, 0x00, 0x58, 0x00
UTF16BE
(或UTF-16BE
):“大端”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) 开头。在 little-endian 机器(我的)上,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 到 utf16 的转换,但如果您正在执行 utf8 到 utf16 的转换,您会担心。
【讨论】:
以上是关于char 类型并将 ASCII 文本重新编码为 UTF-16的主要内容,如果未能解决你的问题,请参考以下文章