getchar 的思考v0.2
2008年7月10日 05:03
通常我们学到的库函数getchar()会从标准输入得到一个字符,其返回值为int(read as an `unsigned char', and cast to `int').返回值为int的原因大致就是为了照顾特殊的EOF吧。
如果运行下面的程序:
int main(void)
{
char a = 0;
while ( (a = getchar()) && (a != EOF)) {
putchar(a);
}
return 0;
}
==========
输入:
Hello,World!
输出:
Hello,World!
会发现居然能够输出整个字符串。其实跟踪一下代码即可发现原因。另外,在手册中还有说明:'getchar' is a macro, defined in `stdio.h'. You can use `getchar' to get the next single character from the standard input stream. As a side effect, `getchar' advances the standard input's current position indicator.这个就解释了为什么会把整个终端输入的所有内容都输出。
==========
这个程序还有更重要的问题是关于getchar()这个(类)函数的使用(返回值)。
RETURNS
The next character (read as an `unsigned char', and cast to `int')
这意味着getchar的返回值会是int。让我们看看代码来深入了解一下为什么getchar要返回一个int值呢?
在glibc的源码中getchar()的实现如下:
(_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) '
? __uflow (_fp) : *(unsigned char *) (_fp)->_IO_read_ptr++)
int
getchar ()
{
int result;
_IO_acquire_lock (_IO_stdin);
result = _IO_getc_unlocked (_IO_stdin);
_IO_release_lock (_IO_stdin);
return result;
}
在C中EOF是一个整型,和任何的char类型都不相同。在上面的代码中_IO_getc_unlocke会返回当前_IO_read_ptr的字符,类型为unsigned char,当读取到结束时就会返回__uflow,_uflow就会返回EOF。因此EOF在glibc中就定义为-1,这个值和任何一个unsigned char都不相同。在_IO_getc_unlocked 返回的时候就要返回一个int值来“照顾”EOF这个特殊角色了。
再请回头看在最开始的测试程序中变量a的类型是char。问题就处在这里了:对于char这种类型是signed char还是unsigned char是由编译器决定的。既然EOF是一个和unsigned char 类型(0x00~0xFF)不同的数据,显然char无论是signed char 还是unsigned char都是无法满足EOF的值,对于a != EOF这个条件就永远无法满足了。这样显然我们期望满足的unsigned char数值(0x00~0xFF),又要满足EOF的数据类型,显然int是比较合适的。
==========
关于while ( (a = getchar()) && (a != EOF))
这里我有意写成这样的原因是想着重说明一下: 对于赋值表达式的值即为赋值以后的左值。即上式同义为while((a = getchar() != EOF)。 还要说一下的是 = 的优先级要比 != 低,因此要给 a = getchar 加括号以提升优先级。
最后要感谢海!