我们假设只有C99 Standard论文和printf
库函数需要根据此标准实现才能使用UTF-16编码,请您澄清一下指定精度的s
转换的预期行为?
s
转换的C99标准版(7.19.6.1)说:
如果不存在l length修饰符,则参数应该是指向字符类型数组的初始元素的指针。数组中的字符被写入(但不包括)终止空字符。如果指定了精度,则不会写入多少个字节。如果未指定精度或大于数组的大小,则数组应包含空字符。
如果存在l长度修饰符,则参数应该是指向wchar_t类型数组的初始元素的指针。数组中的宽字符将转换为多字节字符(每个字符就好像通过调用wcrtomb函数一样,在转换第一个宽字符之前将mbstate_t对象描述的转换状态初始化为零),直到并包括终止的null宽字符。生成的多字节字符被写入(但不包括)终止空字符(字节)。如果未指定精度,则数组应包含空宽字符。如果指定了精度,则写入的字节数不会超过(包括移位序列,如果有的话),并且如果要等于精度给出的多字节字符序列长度,则该数组应包含空宽字符,该函数需要在数组末尾访问一个宽字符。在任何情况下都不会写出部分多字节字符。
我一般都不太了解这一段和语句"如果指定了一个精度,那么写入的字节数不会多于#34;特别是。
例如,让我们采用UTF-16字符串" TEST" (字节序列:0x54,0x00,0x45,0x00,0x53,0x00,0x54,0x00)。
在以下情况下,期望写入输出缓冲区:
然后还有#34;阵列中的宽字符被转换为多字节字符"。这是否意味着首先应将UTF-16转换为UTF-8?如果我希望只使用UTF-16,这很奇怪。
答案 0 :(得分:1)
将评论转换为稍微扩展的答案。
您的实施中CHAR_BIT
的价值是多少?
如果CHAR_BIT == 8
,您无法使用%s
处理UTF-16;您使用%ls
并且您将wchar_t *
作为相应的参数传递。然后,您必须阅读规范的第二段。
如果CHAR_BIT == 16
,则数据中不能有奇数个八位字节。然后你需要知道wchar_t
与char
的关系(它们是否具有相同的大小?它们是否具有相同的符号?)并解释两个段落以产生统一的效果 - 除非您决定让wchar_t
代表UTF-32。
关键是如果CHAR_BIT == 8
不能将UTF-16作为C字符串处理,因为有太多有用的字符用一个字节保持零编码,但这些零字节标记为空的结尾 - 终止字符串。要处理UTF-16,普通char
类型必须是16位(或更大)类型(因此CHAR_BIT > 8
),或者您必须使用wchar_t
(和{{ 1}})。
请注意,规范要求将宽字符转换为合适的多字节表示。
如果您希望本地输出宽字符,则必须使用sizeof(wchar_t) > sizeof(char)
中的fwprintf()
及相关函数,该函数首先在C99中定义。那里的规范与<wchar.h>
的规范有许多共同之处,但有(不出所料)重要的差异。
7.29.2.1 fwprintf函数
...
fprintf()
如果不存在s
长度修饰符,则参数应为指向初始值的指针 包含多字节字符序列的字符数组的元素 从初始换档状态开始。数组中的字符转换为 如果通过重复调用l
函数,转换状态 由mbrtowc
对象描述,在第一个之前初始化为零 多字节字符被转换,并写入(但不包括) 终止null宽字符。如果指定精度,则不超过 写了很多宽字。如果未指定精度或是 大于转换数组的大小,转换后的数组应包含一个 null宽字符。如果存在
mbstate_t
长度修饰符,则参数应为指向初始值的指针l
类型数组的元素。数组中的宽字符是 写入(但不包括)终止空宽字符。如果 指定精度,不超过写入多个宽字符。如果 未指定精度或大于数组(数组)的大小 应包含空宽字符。
答案 1 :(得分:1)
wchar_t
不适用于UTF-16,仅适用于实现定义的固定宽度编码,具体取决于当前的语言环境。使用宽字符API支持可变长度编码根本没有理智的方法。同样,printf
或wcrtomb
等函数使用的多字节表示是实现定义的。如果要使用Unicode编写可移植代码,则不能依赖宽字符API。使用库或滚动自己的代码。
要回答您的问题:fprintf
l
修饰符接受当前语言环境指定的实现定义编码中的宽字符串。如果wchar_t
是16位,这种编码可能是UTF-16的混蛋,但正如我上面提到的,没有办法正确支持UTF-16代理。然后,将此wchar_t
字符串转换为实现定义编码中的多字节char
字符串。这可能是也可能不是UTF-8。指定的精度限制了输出字符串中char
的数量,并增加了不写入部分多字节字符的限制。
这是一个例子。假设宽字符编码是带有32位wchar_t
的UTF-32,并且多字节编码是UTF-8(就像在带有appropriate locale的Linux上一样)。以下代码
wchar_t w[] = { 0x1F600, 0 }; // U+1F600 GRINNING FACE
printf("%.3ls", w);
将完全不打印,因为生成的UTF-8序列有四个字节。仅当您指定至少为4的精度
时printf("%.4ls", w);
将打印角色。
编辑:要回答第二个问题,不,printf
永远不应该写一个空字符。该句子仅表示在某些情况下,需要一个空字符来指定字符串的结尾并避免缓冲区过读。