在 Kernighan & Ritchie 中,它说“当 char 数据类型被签名或无符号取决于机器时,所有可打印字符都是正数。”
有人可以向我解释这条线的含义吗?我的系统已经签署了字符,但即使是负值,比如 -90,printf 也会打印一个字符(即使它不是一个非常熟悉的字符)。
在 Kernighan & Ritchie 中,它说“当 char 数据类型被签名或无符号取决于机器时,所有可打印字符都是正数。”
有人可以向我解释这条线的含义吗?我的系统已经签署了字符,但即使是负值,比如 -90,printf 也会打印一个字符(即使它不是一个非常熟悉的字符)。
ASCII 字符集定义从0x00
到 的代码点0x7F
。它们是用无符号字节值还是有符号字节值表示并不重要,因为这个范围对两者都是通用的。
可打印字符介于0x20
和之间0x7E
,它们都是 ASCII 的一部分。可打印字符一词并没有定义世界上所有可能的可打印字符。相反,它是在 ASCII 领域内定义的。
0x80
从to 到的字节值0xFF
在 ASCII 中没有定义,不同的系统将不同的字符分配给此范围内的值,从而导致许多不同类型的代码页在其 ASCII 范围内相同但在此范围内不同。这也是有符号和无符号字节值不同的范围。
的实现在其输入中printf
遇到键时查找单个字节值。从您作为函数%c
调用者的角度来看,这个字节值可能是有符号或无符号的,但不知道这一点。它只是将这 8 位传递给它所连接的输出流,并且该流在and中发出字符。printf
printf
0x00
0xff
在发出字符的输出管道中,符号的概念没有任何意义。因此,无论您发送 a255
还是 a -1
,都会发出映射到0xFF
特定代码页中的字符。
-90 作为有符号字符被重新解释为无符号字符,在这种情况下,它的值为 166。(-90 和 166 都是十六进制的 0xA6。)
这是正确的。所有二进制数都是正数。你是否认为它是负面的,是你自己的解释。使用常见的二的恭维。
8 位数:10100110 是正数 166,大于 128(最大正符号 8 位数)。
使用有符号算术,数字 166 是 -90。
您看到的是 ascii 值为 166 的字符。
以此为例:
signed char x = -90;
printf("%c", x);
整数提升规则在将其作为参数传递给 之前转换x
为。(请注意,其他答案都没有提到这个细节,并且有几个暗示参数 to仍然是一个有符号字符)。int
printf
printf
标准的第 7.21.6.1.6 节(我使用的是 C11 标准)谈到了%c
标志字符:
如果不存在 l 长度修饰符,则将 int 参数转换为无符号字符,并写入结果字符。
因此整数-90
被转换为无符号字符。这意味着(6.3.1.3.2):
...通过在新类型中可以表示的最大值重复加或减一,直到该值在新类型的范围内,来转换该值。
如果系统上的 unsigned char 取值 0 到 255(几乎可以肯定),那么结果将是 -90 + 256 = 166。(注意:其他答案是指“最低字节”或“十六进制表示”假设二进制补码表示。虽然这非常普遍,但 C 标准不保证它)。
然后将字符 166 写入标准输出,并由您的终端解释。