char 类型并将 ASCII 文本重新编码为 UTF-16
char type and re-encoding ASCII text into UTF-16
我正在使用 libiconv
将我的字符数组转换为 UTF-16 字符串。我有疑问。
iconv
函数的签名
size_t iconv(iconv_t cd,
const char* * inbuf, size_t *inbytesleft,
char* * outbuf, size_t *outbytesleft);
这意味着,char
用于保存要转换为的任何类型的字符(char 与 wide char)。
我在学校的 C 老师教我,对于奇怪或不可读的字符,我们应该使用 wchar_t。我现在很困惑。
我在 input = "KOTEX"
上测试了这个方法作为 ASCII
编码类型,并希望输出另一个双倍长度的字符串编码为 UTF-16
。它立即失败。但是,如果我将目标代码页更改为 UTF-8
,它会起作用,但返回的数据会丢失。这是为什么?
iconv
的缓冲区参数实际上是 char *
但这并不意味着它们实际上表示 C 字符串。 (如果界面改用 uint8_t*
可能不会那么令人困惑,但这是不合时宜的;iconv
在 stdint.h
之前就存在了)
Posix 标准(和 Linux 联机帮助页)试图阐明这一点:
The type of inbuf
and outbuf
, char **
, does not imply that the objects pointed to are interpreted as null-terminated C strings or arrays of characters. Any interpretation of a byte sequence that represents a character in a given character set encoding scheme is done internally within the codeset converters. (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
,取决于机器是大端还是小端;转换后的字符串以 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
(未经修饰的字节序规范)总是以 BOM 开头的事实意味着您必须记住在输出缓冲区中提供一个额外的(2 字节)字符。否则,您将得到 E2BIG
.
在所有这三种编码中,basic multilingual plane (BMP) require two (two-byte) character positions, a so-called surrogate pair 之外的字符。所有 ascii 字符都在 BMP 上,因此您无需担心 ascii 到 utf16 的转换,但如果您正在执行 utf8 到 utf16,则您会担心。
我正在使用 libiconv
将我的字符数组转换为 UTF-16 字符串。我有疑问。
iconv
函数的签名size_t iconv(iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);
这意味着,
char
用于保存要转换为的任何类型的字符(char 与 wide char)。 我在学校的 C 老师教我,对于奇怪或不可读的字符,我们应该使用 wchar_t。我现在很困惑。我在
input = "KOTEX"
上测试了这个方法作为ASCII
编码类型,并希望输出另一个双倍长度的字符串编码为UTF-16
。它立即失败。但是,如果我将目标代码页更改为UTF-8
,它会起作用,但返回的数据会丢失。这是为什么?
iconv
的缓冲区参数实际上是 char *
但这并不意味着它们实际上表示 C 字符串。 (如果界面改用 uint8_t*
可能不会那么令人困惑,但这是不合时宜的;iconv
在 stdint.h
之前就存在了)
Posix 标准(和 Linux 联机帮助页)试图阐明这一点:
The type of
inbuf
andoutbuf
,char **
, does not imply that the objects pointed to are interpreted as null-terminated C strings or arrays of characters. Any interpretation of a byte sequence that represents a character in a given character set encoding scheme is done internally within the codeset converters. (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
,取决于机器是大端还是小端;转换后的字符串以 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
(未经修饰的字节序规范)总是以 BOM 开头的事实意味着您必须记住在输出缓冲区中提供一个额外的(2 字节)字符。否则,您将得到 E2BIG
.
在所有这三种编码中,basic multilingual plane (BMP) require two (two-byte) character positions, a so-called surrogate pair 之外的字符。所有 ascii 字符都在 BMP 上,因此您无需担心 ascii 到 utf16 的转换,但如果您正在执行 utf8 到 utf16,则您会担心。