⽤法charch=getchar()正确性详解
《C陷阱与缺陷》 chap5.1
#include <stdio.h>
int main()异步fifo怎么过域
{
char c; /* 改成:int c 就正确了 */
while( ( c = getchar() ) != EOF )免费游戏大全试玩
{
putchar( c );
putchar函数}
return 0;
}
getchar函数在⼀般情况下返回的是标准输⼊⽂件中的下⼀个字符,当没有输⼊时返回EOF(⼀个在头⽂件stdio.h中被定义的值,不同于任何⼀个字符,⼀般C语⾔实现定义为-1)。这个程序乍⼀看似乎把标准输⼊复制到标准输出,实则不然。
原因在于程序中的变量c被声明为char类型,⽽不是int类型。这意味着c⽆法容下所有可能的字符,特别是,可能⽆法容下EOF。因此,最终结果存在以下⼏种可能:
1)某些合法的输⼊在被截断后,使得c的取值和EOF相同;这时程序将在⽂件复制的中途终⽌;
2)c根本不可能取到EOF这个值;这时程序陷⼊死循环;
springsecurity第三方登录3)程序表⾯上似乎能够正常⼯作,但完全是因为巧合。尽管函数getchar的返回结果在赋值给char类型的变量c时会发⽣“截断”操作,尽管while语句中⽐较运算的操作数不是函数getchar的返回值,然⽽令⼈惊讶地是许多编译器对上述表达式的实现并不正确。这些编译器确实对函数getchar的返回值做了截断处理,并把低端直接部分赋给了变量c。但是,它们在⽐较表达式中并不是⽐较c与EOF,⽽是⽐较getchar函数的返回值与EOF,编译器如果采取这种做法,上⾯的例⼦程序看上去就能够“正常”运⾏了。
许多初学者都习惯⽤ 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 |while里面continue
| FF | 00 00 00 FF | FF FF FF FF |
| FE | 00 00 00 FE | FF FF FF FE |
---------------------------------------
由上表可知,当 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循环。
综上所述,使⽤ char 型变量接收 fgetc 等函数的返回值是错误的,我们必须使⽤ int 型变量接收这些函数的返回值,然后判断接收到的值是否 EOF.只有判断发现该返回值并⾮ EOF,我们才可以把该值赋值给 char 型变量。
同理,C++ 中,⽤ char 型变量接收 ()的返回值也是错误的。不过,把 char 型变量当作参数传递给 则是正确的。例如:
char c = (); // 错误,理由同上
char c;
(c); // 正确
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论