加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

printf字段宽度:字节还是字符?

发布时间:2020-12-16 09:27:42 所属栏目:百科 来源:网络整理
导读:printf / fprintf / sprintf系列支持 格式说明符中的宽度字段.我有个疑问 对于(非宽)char数组参数的情况: 宽度字段应该是字节还是字符? 如果char数组是什么(正确 – 事实上)行为 对应(比方说)一个原始的UTF-8字符串? (我知道通常我应该使用一些宽的char类
printf / fprintf / sprintf系列支持
格式说明符中的宽度字段.我有个疑问
对于(非宽)char数组参数的情况:

宽度字段应该是字节还是字符?

如果char数组是什么(正确 – 事实上)行为
对应(比方说)一个原始的UTF-8字符串?
(我知道通常我应该使用一些宽的char类型,
那不是重点)

例如,在

char s[] = "nixc3xb1o";  // 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<stdio.h>
#include<locale.h>
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','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它对我来说还可以.

解决方法

它将导致输出五个字节.和五个字符.在ISO C中,字符和字节之间没有区别.字节不一定是8位,而是定义为char的宽度.

8位值的ISO术语是八位字节.

你的“ni?o”字符串在C环境方面实际上是五个字符宽(当然没有空终结符).如果终端上只显示四个符号,那几乎可以肯定是终端的功能,而不是C的输出功能.

我不是说C实现无法处理Unicode.如果CHAR_BITS被定义为32,它可以很容易地做到UTF-32.由于UTF-8是一个可变长度编码会更难,但几乎所有问题都有办法:-)

根据您的更新,您可能会遇到问题.但是,我没有在我的设置中看到您描述的行为具有相同的区域设置.在我的情况下,我在最后两个printf语句中得到相同的输出.

如果您的设置只是在第一个|之后停止输出(我假设你的意思是中止但是,如果你的意思是整个程序中止,那就更严重了),我会提出GNU的问题(首先尝试你的特定发行版程序).你已经完成了所有重要的工作,例如生成一个最小的测试用例,所以如果你的发行版没有完全达到目的,大多数人都不应该对最新版本进行操作.

顺便说一句,我不确定你的意思是检查od输出.在我的系统上,我得到:

pax> ./qq | 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   |   A 261   B   |  n
         7c  41  b1  42  7c  0a  7c  41  b1  42  7c  0a
0000034

所以你可以看到输出流包含UTF-8,这意味着它是必须解释它的终端程序. C / glibc根本没有修改输出,所以也许我只是误解了你想说的内容.

虽然我刚刚意识到你可能会说你的od输出也只有那条线上的起始条(不像我看起来没有问题),这意味着它在C / glibc中是错的,不是错的终端默默地丢弃角色(说实话,我希望终端能够丢弃整行或者只是违规的字符(即输出| A) – 你刚刚得到的事实似乎排除了一个终端问题).请澄清一下.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读