C中的符号扩展,char>unsigned char

4
当我在阅读K&R时,我对这段代码感到困惑:
#include "syscalls.h"
int getchar(void)
{
    char c;

    return (read(0, &c, 1) == 1) ? (unsigned char)c : EOF;
}

据说在这段代码中使用unsigned char是为了避免符号扩展带来的错误。这是我能想到唯一的情况,并给出下面的示例代码:
char c = 0xf0; //11110000, just make highest bit > 1
printf("%i\n",(int)(unsigned char)c);
printf("%i\n",(int)c);

Output:  240 // 0...011110000
         -16 // 1...111110000

实际上,ASCII 只有 0~127,最高位不能被赋值为 1。那么为什么在 K&R 中将 char 强制转换为 unsigned char?


你为什么认为char需要限制在ASCII字符集中? - Paul R
@PaulR 谢谢,但你能教我如何使用不带转换的 getchar() 打印并获取错误输出吗 :) 我的电脑:Ubuntu13 x64 - pupu007
3个回答

5

ASCII字符编码范围限制在0..127,但是并不仅仅是ASCII字符可以被read读取 - 在K&R中,它可以获取整个char值的0..255范围。

这就是为什么getchar返回一个int,因为它必须能够返回任何char值以及一个特殊的EOF值,该值与所有其他字符都不同。

通过将字符转换为unsigned char后再将其提升为int进行返回,可以防止128..255的值被符号扩展。如果允许符号扩展,您将无法区分255(这将符号扩展为所有1位)和EOF(它是-1,所有1位)之间的差异。


我不完全确定您使用K&R来学习语言的策略是否明智。自那时以来,C语言已经发生了很大变化。从记忆中,即使最新的K&R书籍也是针对C89 / 90 ANSI标准(在ISO基本上接管责任之前),而且语言已经经历了两次大规模升级。


谢谢,但你能教我如何使用不带转换的getchar()打印和获取错误输出吗?我的电脑是Ubuntu13 x64。 - pupu007
我使用这本书来区分C99和C90的不同之处。K&R不适合初学者。 - pupu007
@pup007,创建一个文件,其中包含一个字节0xff,后跟一个可打印的字符串。您会发现从char 255到int的转换将给出-1(eof),并且它永远不会读取其他字符,当然假设chars是有符号的,chars是8位的,并且主机中的其他许多东西在过去20年中可能已经更改了。 - paxdiablo
谢谢,我明白了。getchar()函数从标准输入读取字符,但也可以重定向到文件中。(一切皆有可能):) - pupu007
自那时起,该语言已经进行了两次大规模升级。@paxdiablo您介意分享一下这两次升级有哪些变化吗? - qwerty_url

1
无符号字符型变量的取值范围在0到255之间,如需强制类型转换,请遵循同一书中的注释。
Whether plain chars are signed or unsigned is machine-dependent, but printable characters are always positive.

现在,如果我们谈论C标准,那么它如下所示。
The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char.

另一个时代错误的例子。大多数地区在128-255范围内都有可打印字符。 - Klas Lindbäck
@KlasLindbäck 我试图展示对这种类型转换的赞成所做的评论。 - Dayal rai
1
我的评论并不是对你的答案进行批评,而只是支持paxdiablo的观点,即K&R的书不适合学习更新版本的C语言的一种观察。 - Klas Lindbäck
例如,@KlasLindbäck? - pupu007
1
@pupu007 除了普通的7位ASCII码以外,还有其他编码方式。例如:ISO8859-1和CP1252。 - Klas Lindbäck

1
return (read(0, &c, 1) == 1) ? (unsigned char)c : EOF;

意思是:读取一个字符到c中;如果你至少能读取一个字符,则返回它;否则返回(int类型的)EOF。

注意,getchar() 返回一个int类型的值,因此需要进行 char->unsigned char->int 的转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接