2011-12-21 11 views
6

当下面的代码编译它进入一个无限循环比较无符号的字符和EOF

​​

GCC编译器还提供了有关编译

abc.c:13:warning: comparison is always true due to limited range of data type 

代码警告运行正常时unsigned char是如预期的那样由charint取代,即它终止。
但代码也运行良好unsigned int以及。 因为我已经阅读EOF被定义为-1stdio.h那么为什么此代码无效的无符号字符,但运行良好的无符号整型。

+2

基本相同[龟etc不识别EOF](http://stackoverflow.com/questions/3977223/fgetc-does-not-identify-eof)。我认为我们每周至少有一次这类问题。 – 2011-12-21 08:28:11

+2

另请参见http://c-faq.com/stdio/getcharc.html – 2011-12-21 08:30:31

+0

[为什么必须将用于保存getchar的返回值的变量声明为int?](http://stackoverflow.com/questions/18013167/why-must-the-variable-used-to-hold-getchars-return-value-be-declared-as-int) – 2017-05-15 12:15:51

回答

7

金科玉律写这行之后是

while ((ch = fgetc(stdin)) != EOF) 

ch应该int。你的制作ch可爱的把戏无符号的失败,因为EOF是一个符号整数数量。

好了,现在让我们进入深度......

第1步:

ch=fgetc(fp) 

fgetc()回报-1(签署的int)。按照C ch的黄金法则获取全部为1的位的最后八位字节。因此价值255。的

ch = fgetc(fp); 
执行后的 ch字节图案

因此将是

11111111 

步骤2:

ch != EOF 

现在EOF符号整数chunsigned char ...

我再次提到C的黄金法则...小家伙ch转化为大尺寸int对比之前,所以它的字节模式现在

00000000000000000000000011111111 = (255)10 

EOF

11111111111111111111111111111111 = (-1)10 

没有办法,他们可以等于... ....因此,引导以下while循环的陈述

while ((ch = fgetc(stdin)) != EOF) 

永远不会评估为false ...

因此无限循环。

+1

黄金法则**总是匹配括号**。在这两个例子中你都缺少'''',它必须是'while((ch = fgetc(stdin))!= EOF)''。 – Jens 2012-05-29 08:20:30

+0

我只是让你明确的答案看起来更好。不过,请您详细说明您想向您表达这种模式:'... =(255)10'和'... =(-1)10'? – alk 2016-06-15 19:33:35

+0

@alk这个答案是由“学生我”写的,因此符号不一致。 (255)10表示以10为底的255 – bashrc 2016-06-16 06:08:50

1

你需要使用一个int

龟etc()专门返回一个int,以便它可以指示文件的末尾

运行良好与符号的字符,因为EOF(-1)范围内但如果你在一个字符用值大于127

阅读使用int它会打破,将它转换为一个char你检查EOF

+0

我知道int应该用于正确的代码,但我想知道为什么无符号字符不工作,但无符号int作品... – 2011-12-21 08:20:22

+0

如何-1是在无符号整数范围 – 2011-12-21 08:25:32

+2

阅读整数推广规则。 – 2011-12-21 08:40:21

0

将无符号整数与带符号整数进行比较时,会将有符号整数转换为无符号整数并进行比较。因此,当你用unsigned int'ch'读取文件时,读取EOF会给你2^32 + 1(在一个4字节的int机器上),当与EOF比较时,它将EOF转换为无符号,这也是2^32 + 1,因此程序停止!

如果您使用无符号字符ch,读取文件时读取EOF返回2^32 + 1,这将被转换为无符号字符,它将值截断为前8位(在1字节字符机器上)并给出255的输出。因此,您正在比较255和2^32 + 1,导致无限循环。

这里的问题在比较之前会被截断。

如果使用

while((ch = fgetc(fp))!=(unsigned char)EOF) 
    printf("%c",ch); 

您程序将运行正常!

6

有几个隐式转换正在进行。它们与具体的警告并不相关,但我将它们包含在这个答案中,以显示编译器对该表达式的真正用处。

  • 在你的例子中ch是unsigned char类型。
  • EOF保证是int类型(C99 7.19.1)。

所以表达式相当于

(unsigned char)ch != (int)EOF 

整数提升规则用C将隐式无符号的字符转换为unsigned int类型:

(unsigned int)ch != (int)EOF 

然后平衡规则(又名通常的算术转换)在C中会隐式地将int转换为unsigned int,因为每个操作数都必须有sa我类型:

(unsigned int)ch != (unsigned int)EOF 

你的编译器EOF可能是-1:

(unsigned int)ch != (unsigned int)-1 

其中,假设32位CPU,相同

(unsigned int)ch != 0xFFFFFFFFu 

字符绝不能有如此高的价值,因此是警告。

2

我也遇到过这个问题。我的解决方案是使用feof()。

unsigned int xxFunc(){ 
    FILE *fin; 
    unsigned char c; 
    fin = fopen("...", "rb"); 
    if(feof(fin) != 0) return EOF; 
    c = fgetc(fin); 
    fclose(fin); 
... 
} 

而且您可以定义一个int变量来与EOF进行比较。例如:

int flag = xxFunc(); 
while(flag != EOF) {...} 

这对我有用。

**重要更新* **

使用我之前提到的方法后,我发现了一个严重的问题。 012offeof()不是打破while循环的好方法。 这是它的原因。 http://www.gidnetwork.com/b-58.html

所以我找到了一个更好的方法来做到这一点。我使用一个int变量来做到这一点。这里:

int flag; 
unsigned char c; 
while((flag = fgetc(fin)) != EOF) 
{ 
    //so, you are using flag to receive, but transfer the value to c later. 
    c = flag; 
    ... 
} 

经过我的测试,这个工程。

0

产生棉绒警告与该种类的实施

与EOF比较类型 '字符'

// read the data in a buffer 
611  ch = getc(csv_file); 
612  while (ch != EOF) 

FIX:

// read the data in a buffer 
    while ((ch = getc(csv_file)) != EOF)