写C时我们经常会使用类似下面的代码来循环读字符直到输入截至:
char c;
while ((c = getchar()) != EOF) {
}
但其实这段代码是有陷阱的,让我们一一分析。
1. 明确前提
1.1. char有无符号
根据ANSI C标准:char可以被定义为有符号的也可以被定义为无符号的,具体由编译器决定。
根据GCC定义:gcc中char是否有符号由操作系统提供的接口ABI决定,可以使用-funsigned-char和-fsigned-char参数手动指定。
1.2. EOF的值
根据ANSI C标准:EOF可以被定义为与任意char类型的值都不相同的值。
根据GCC:EOF被定义为-1,可以在stdio.h中找到,如图:
2. 导致的问题
我们可以立即发现,假设char被定义为无符号的,且EOF又是-1的情况下,((c = getchar()) != EOF)明显是有问题的。甚至,根据ANSI C的定义,EOF要被定义为任意char类型的值都不相同,并且又要多出一个返回EOF的可能性。getchar()这个函数的返回值不可能是char。实际上,通过man getchar我们可以清楚的看到,getchar()为了能包含返回EOF的可能,它的返回值类型被定义为int,如图:
所以,使用我们定义的char类型的c去接受getchar()的返回值再与EOF比较是非常不科学的。
引用《C陷阱与缺陷》5.1节所述,导致的结果有3种可能:
而根据我雪测试,使用-funsigned-char参数指定后,导致的结果是第二种,程序会进入死循环。
3. 结论
由此我们可以看出,开头所述的代码不具有可移植性,解决办法也很简单:读入时使用signed char定义c即可。
title: C语言杂记(1):暗藏玄机的char和getchar
time: 2018-09-13 23:25
tags: C
category: Study
真tm吊!!!
我的c反正是白学了