副标题#e#
很多初学者都习习用 char 型变量吸收 getchar、getc,fgetc 等函数的返 回值,其实这么做是差池的,而且隐含着足乃至命的错误。getchar 等函数的返 回值范例都是 int 型,当这些函数读取堕落可能读完文件后,会返回 EOF.EOF 是一个宏,尺度划定它的值必需是一个 int 型的负数常量。凡是编译器城市把 EOF 界说为 -1.问题就出在这里,利用 char 型变量吸收 getchar 等函数的返 回值会导致对 EOF 的辨认堕落,可能错把好的数据误认为是 EOF,可能把 EOF 误认为是好的数据。譬喻:
int c; /* 正确。应该利用 int 型 变量吸收 fgetc 的返回值 */
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
如上例所示,我们许多时候都需 要先用一个变量吸收 fgetc 等函数的返回值,然后再用这个变量和 EOF 较量, 判定是否已经读完文件。上面这个例子是正确的,把 c 界说为 int 型担保了它 能正确吸收 fgetc 返回的 EOF,从而担保了这个较量的正确性。可是,假如把 c 界说为 char 型,则会导致意想不到的效果。
首先,因为 fgetc 等函 数的返回值是 int 型的,当赋值给 char 型变量时,会产生降级,从而导致数 据截断。譬喻:
———————————
| 十进制 | int | char |
|——–|————–|— —-|
| 10 | 00 00 00 0A | 0A |
| -1 | FF FF FF FF | FF |
| -2 | FF FF FF FE | FE |
———————————
在此,我们假设 int 和 char 别离是 32 位和 8 位的。由上表可得,从 int 型到 char 型,损 失了 3 个字节的数据。而当我们要拿 char 型和 int 型较量的时候,char 型 会自动进级为 int 型。char 型进级为 int 型后的值会因为它到底是 signed char 照旧 unsigned char 而有所差异。不幸的是,假如我们没有利用 signed 可能 unsigned 来修饰 char,那么我们无从知晓 char 到底是指 unsigned char 照旧指 signed char,因为这是由编译器抉择的。不外,无论 char 是 signed 的也好,unsigned 的也罢,都不能改变利用 char 型变量吸收 fgetc 等函数的返回值是错误的这个事实。独一能改变的是该错误导致的效果。前面我 们说了,char 型和 int 型较量时,char 会自动进级为 int,下面我们来看看 signed char 和 unsigned char 在转换成 int 后,它们的值有什么差异:
—————————————
| char | unsigned | signed |
|——-|—————|– ———–|
| 10 | 00 00 00 0A | 00 00 00 0A |
| FF | 00 00 00 FF | FF FF FF FF |
| FE | 00 00 00 FE | FF FF FF FE |
—————————– ———-
#p#副标题#e#
由上表可知,当 char 是 unsigned 的时候,其转换为 int 后的值是正数。也就是说,如果我们把 c 界说为 char 型变量,而编译器默认 char 为 unsigned char,那么以下表达式将永远创立。
(c = fgetc (fp)) != EOF /* c 的值永远为正数,而尺度划定 EOF 为负数 */
也就是说以下轮回是一个死轮回。
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
读到这 里,大概有些读者伴侣会说:“那么我明晰把 c 界说为 signed char 型 的就没问题了吧!”很遗憾,就算把 c 界说为 signed char,仍然是错误 的。假设 fgetc 等函数读到一个字节的值为 FF,那么返回值就是 00 00 00 FF.把这个值赋值给 c 后, c 的值酿成 FF.然后 c 的值为了和 EOF 较量,会 自动进级为 int 型的值,也就是 FF FF FF FF.从而导致以下表达式不创立。
(c = fgetc(fp)) != EOF /* 读到值为 FF 的字符,误认为 EOF */
也就是说以下轮回在没有读完文件的环境下提前退出。
while ( (c = fgetc(fp)) != EOF )
{
putchar (c);
}
综上所述,利用 char 型变量吸收 fgetc 等函数的 返回值是错误的,我们必需利用 int 型变量吸收这些函数的返回值,然后判定 吸收到的值是否 EOF.只有判定发明该返回值并非 EOF,我们才可以把该值赋值 给 char 型变量。
同理,C++ 中,用 char 型变量吸收 cin.get() 的 返回值也是错误的。不外,把 char 型变量看成参数通报给 cin.get 则是正确 的。譬喻:
char c = cin.get(); // 错误,来由同上
char c;
cin.get(c); // 正确