printf / fprintf / sprintf系列支持
格式说明符中的宽度字段.我有个疑问
对于(非宽)char数组参数的情况:
宽度字段应该是字节还是字符?
如果char数组是什么(正确 – 事实上)行为
对应(比方说)一个原始的UTF-8字符串?
(我知道通常我应该使用一些宽的char类型,
那不是重点)
例如,在
char s[] = "ni\xc3\xb1o"; // utf8 encoded "niño"
fprintf(f,"%5s",s);
这个函数应该只尝试输出5个字节
(普通C chars)(并且你承担了错位的责任
或两个字节导致文本字符的其他问题)?
或者是否应该尝试计算“文本字符”的长度
阵列? (根据当前的语言环境对其进行解码?)
(在这个例子中,这相当于发现字符串有
4个unicode字符,所以它会为填充添加一个空间).
更新:我同意答案,printf家族没有合情合理
将普通C字符与字节区分开来.问题是我的glibc doest似乎没有
完全尊重这个概念,如果先前已经设置了区域设置,并且如果
一个有(今天最常用)LANG / LC_CTYPE = en_US.UTF-8
例证:
#include
#include
main () {
char * locale = setlocale(LC_ALL, ""); /* I have LC_CTYPE="en_US.UTF-8" */
char s[] = {'n','i', 0xc3,0xb1,'o',0}; /* "niño" in utf8: 5 bytes, 4 unicode chars */
printf("|%*s|\n",6,s); /* this should pad a blank - works ok*/
printf("|%.*s|\n",4,s); /* this should eat a char - works ok */
char s3[] = {'A',0xb1,'B',0}; /* this is not valid UTF8 */
printf("|%s|\n",s3); /* print raw chars - ok */
printf("|%.*s|\n",15,s3); /* panics (why???) */
}
因此,即使设置了非POSIX-C语言环境,仍然printf似乎有正确的概念来计算width:bytes(c plain chars)而不是unicode chars.没关系.但是,当给定一个在其语言环境中无法解码的char数组时,它会无声地发生恐慌(它会中止 – 在第一个’|’之后没有任何内容打印 – 没有错误消息)…只有当它需要计算一些宽度时才会出现.我不明白为什么它甚至会尝试从utf-8解码字符串,当它不需要/必须时.这是glibc中的错误吗?
用glibc 2.11.1(Fedora 12)测试(也是glibc 2.3.6)
注意:它与终端显示问题无关 – 您可以通过管道检查输出到od:$./a.out | od -t cx1这是我的输出:
0000000 | n i 303 261 o | \n | n i 303 261 | \n
7c 20 6e 69 c3 b1 6f 7c 0a 7c 6e 69 c3 b1 7c 0a
0000020 | A 261 B | \n |
7c 41 b1 42 7c 0a 7c
更新2(2015年5月):这个有问题的行为has been fixed在较新版本的glibc中(从2.17开始,似乎).使用glibc-2.17-21.fc19它对我来说还可以.