int ch = getchar()?

引言

学习C语言中你肯定遇到过这样的代码;

char ch;
while ((ch = getchar()) != EOF)
    putchar(ch);

因为getchar()是从键盘上获取一个字符,所以很多人都会用char类型的变量来接受getchar的返回值,看起来没问题,但是这样写很可能导致循环永不终止,或者也可能提前结束。

函数与EOF介绍

getchar()在读取字符时,正常情况下把该字符从unsigned char转换为int类型返回,若出错或读到文件结尾则返回EOF。

EOF是什么呢? EOF就是End Of File 文件结束标志,在C语言中被宏定义为 -1(hex:0xffffffff)

char ch = getchar()错在哪里?


看到这,你可能会说:既然EOF只是值为-1的负整数,这不是在char的表示范围-128~127内吗?用char保存返回值有何不可?
-1真的一定在char的表示范围内吗?我们可以在头文件limits.h中看到如下定义:
/* Minimum and maximum values a `signed char' can hold.  */
#define SCHAR_MIN	(-128)
#define SCHAR_MAX	127

/* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
#define UCHAR_MAX	255

/* Minimum and maximum values a `char' can hold.  */
#ifdef __CHAR_UNSIGNED__
    #define CHAR_MIN	0
    #define CHAR_MAX	UCHAR_MAX
#else
    #define CHAR_MIN	SCHAR_MIN
    #define CHAR_MAX	SCHAR_MAX
#endif

由此可见,在头文件内并没有规定char是有符号的,所以char类型是否有无符号是由编译器决定的。
当char是无符号的时候,-1就不在char的表示范围内,这时使用char保存返回值也就有问题了。实际上即使你所用的编译器默认定义char是有符号的,上面编写的代码也会带来意想不到的结果,下面我们来分情况讨论。

1. char默认是无符号的


这种情况会导致循环无法终止。假定我们遇到错误/读到文件末尾,getchar函数返回EOF,这时由于ch是char类型,只有一个字节,而EOF是int类型,有四个字节却要保存在一个字节中,EOF的值会被截断,ch也就等于0xff,又因为ch要与EOF比较,ch就要整形提升成为0x000000ff(因为ch是无符号的,也就是0扩展),永远不可能等于EOF,循环也就永远不会终止。

2. char默认是有符号的


这种情况可能导致循环提前终止。同样假定我们遇到错误/读到文件末尾,getchar函数返回EOF,前面都一样,但是在与EOF比较的时候,由于ch是有符号的,其扩展得0xffffffff,等于EOF。因此循环是可以终止的,但是如果我们在遇到错误/读到文件末尾之前读到了一个值为0xff的字节,循环就会同碰到EOF一样终止。

正确的代码

char ch;
while ((ch = getchar()) != EOF)
    putchar(ch);

这种情况就不会有问题。即使我们在遇到错误/读到文件末尾之前读到了一个值为0xff的字节,由于ch是int类型,而getchar是将读到的字符由unsigned char转为int作返回值,则该字节的值经符号扩展再赋值给ch,ch就等于0x000000ff,不会等于EOF,也就不会提前终止了。

而且,当我们查看getchar的介绍时,我们会发现getchar()定义的返回值也是int类型的

int getchar(void);

综上,这就是为什么要用int类型而不是char类型来保存C语言字符读取函数的返回值。

本文转载自:https://seineo.github.io/int-ch-getchar.htm

你可能感兴趣的:(C,c语言,开发语言,后端)