C 如何打印具有或不具有多字符的长度相同的字符串?

C 如何打印具有或不具有多字符的长度相同的字符串?,c,character-encoding,C,Character Encoding,我正在做K&R书中的练习1-22。它要求在字符串中预定义的字符数之后折叠长行(即进入新行) 当我测试这个程序时,它运行得很好,但是我看到一些行比它们应该的更早“折叠”。我注意到出现特殊字符的是线条,例如: öşçğ 因此,我的问题是,如何确保打印行的最大长度相同,有或没有多字符?代码中会发生什么? K&R是在所有字符都编码在一个字符上的时代编写的。此类编码标准的示例为或 如今,领先的编码标准是UNICODE,它有多种风格。使用可变长度方案,编码用于表示8位字节上的数千个unicode字符: a

我正在做K&R书中的练习1-22。它要求在字符串中预定义的字符数之后折叠长行(即进入新行)

当我测试这个程序时,它运行得很好,但是我看到一些行比它们应该的更早“折叠”。我注意到出现特殊字符的是线条,例如:

öşçğ


因此,我的问题是,如何确保打印行的最大长度相同,有或没有多字符?

代码中会发生什么?

K&R是在所有字符都编码在一个字符上的时代编写的。此类编码标准的示例为或

如今,领先的编码标准是UNICODE,它有多种风格。使用可变长度方案,编码用于表示8位字节上的数千个unicode字符:

  • ascii字符(即0x00到0x7F)在单个字节上编码
  • 所有其他字符按2到4字节编码
因此,列表中的和其他字节被编码为2个连续字节。不幸的是,标准C库和K&R算法没有管理变量编码。因此,每个特殊字符都被计算为两个,这样算法就被欺骗了

如何解决它?

没有简单的方法。必须区分内存中字符串的长度和显示字符串时字符串的长度

我可以提出一个使用编码方案属性的技巧:无论何时计算字符串的显示长度,只要忽略内存中符合条件c&0xC0==0x80的字符c即可

另一种方法是使用宽字符
wchar\u t
/
win\u t
(需要头
wchar.h
)而不是
char
/
int
,并使用
getwc()
/
而不是
getc()
/
putc()
。如果在您的环境中
sizeof(wchar\u t)
为4,则您将能够使用unicode,只需使用宽字符和宽库函数,而不是K&R中提到的普通函数。但是如果

sizeof(wchar\u t)
较小(例如2),您可以正确使用较大的unicode子集,但在某些情况下仍可能遇到对齐问题

与注释中一样,您的字符串可能是用UTF-8编码的。这意味着一些字符,包括您提到的字符,使用了多个字节。如果您只是通过计算字节数来确定输出的宽度,那么您的计算值可能太大

要正确确定具有多字节字符的字符串中的字符数,请使用函数,如

如果要逐字符计数,可以使用查找字符串中第一个字符的字节数


这当然超出了K&R书的范围。它是在使用多字节字符之前编写的。

我猜您的字符串是在中编码的,其中多字节代码点中第一个字节之后的所有字节都遵循模式
10xxxxxx
。在计算长度时忽略这些字节,并确保不会分解多字节序列。希望您不会处理分解字符(其中变音符号与基本字符分开)。使用表情符号的属性处理表情符号也是分解字符主题的一种变体。接下来是有趣的时刻。欢迎来到Stack Overflow。请尽快阅读这两页。我们将帮助您修复代码,这些代码显示了解决问题的诚实尝试,并描述了您遇到的问题。如果没有代码,您的问题可能会被认为“过于宽泛”或“因为缺少MCVE()”而脱离主题。请特别阅读关于grapheme群集的内容。当然,您完全正确地使用了
mbrlen()
!但是K&R的第一章实际上是关于基础的。它使用的唯一库函数是基本的I/O函数,计数字符和行是通过循环来处理的。我试图理解这个函数,但做不到。随着我逐渐熟悉指针和C语言,我一定会尝试一下。谢谢你的回答。我可以问一下
c&0xC0==0x80
条件意味着什么吗?二进制中
c&0xC0==0x80
0xC0
的UV是
1100 0000
<代码>&
确保存在0的所有位都被清除为0(K&R关于位逻辑运算的第2.9章)。因此,如果将
c
的二进制表示形式设置为
xyzzz
,则
c&0xC0
将导致
XY00 0000
。二进制中的0x80是
1000 0000
。因此
c&0xC0==0x80
为真,当且仅当二进制中的
c
类似于
10zzzzzz
。如果查看,您会注意到只有编码为
10xx xxxx
的bute才是多字节编码的后续字节。