以char类型存储EOF(文件结尾)字符


11

我读过丹尼斯·里奇(Dennis Ritchie)的《 C编程语言》一书,该书int必须用于容纳EOF的变量-使其足够大以使其可以容纳EOF值-不能char。但是以下代码可以正常工作:

#include<stdio.h> 

main()  { 
  char c; 
  c=getchar(); 
  while(c!=EOF)  { 
    putchar(c); 
    c=getchar(); 
  } 
} 

没有更多输入时,getchar返回EOF。在上面的程序中,c具有char类型的变量能够成功保存它。

为什么这样做?根据上述书籍中的解释,该代码不起作用。



5
如果您读取带有值的字符,则此代码可能会失败0xff。将结果存储getchar()在a中int可以解决该问题。您的问题与comp.lang.c FAQ中的问题12.1基本相同,这是一个很好的资源。(另外,main()应该是int main(void),并且return 0;在收盘前添加a也不会受到损害}。)
Keith Thompson

1
@delnan:链接的文章关于Unix如何对待control-D不太正确。它不会关闭输入流;它只会导致在控制台上阻塞的任何fread()立即返回所有尚未读取的数据。许多程序将fread()的零字节返回解释为表示EOF,但实际上该文件将保持打开状态并能够提供更多输入。
2015年

Answers:


11

您的代码似乎可以正常运行,因为隐式类型转换偶然发生在正确的事情上。

getchar()返回一个int,其值适合unsigned char或的范围EOF(必须为负,通常为-1)。请注意,EOF它本身不是字符,而是一个信号,表明不再有可用的字符。

从中存储结果getchar()c,有两种可能性。任何一种类型char都可以代表值,在这种情况下,即为的值c。或类型char 不能代表值。在这种情况下,尚不确定会发生什么。Intel处理器只是将不适合新类型的高位斩掉(有效地降低的模256值char),但是您不应该依赖于此。

下一步是比较cEOF。由于EOF是一个intc将被转换为一个int为好,保持存储在所述值c。如果c可以存储的值EOF,则比较会成功,但如果c存储该值,则比较会失败,是因为有信息不可挽回的损失,而转换EOF到类型char

看来您的编译器选择使char类型签名,并使值EOF足够小以适合char。如果char未签名(或使用过unsigned char),则测试将失败,因为unsigned char无法保存的值EOF


另请注意,您的代码还有第二个问题。由于EOF不是字符本身,而是您将其强制为一种char类型,因此很可能会有一个字符被误解为是EOF,对于一半可能的字符,如果可以正确处理它们,则是不确定的。


胁迫键入char该范围以外的值CHAR_MIN.. CHAR_MAX将需要要么产生一个实现定义值,收率其中实现定义为陷阱表示,或提高实现定义的信号的位模式。在大多数情况下,实现必须要做很多额外的工作才能做除二进制补码减少以外的任何事情。如果标准委员会的成员赞成这样的想法,即应该鼓励编译器在没有其他理由的情况下实现与大多数其他编译器一致的行为...
supercat

...我认为这样的强制是可靠的(并不是说代码不应该记录其意图,但是(signed char)x应该将其视为更清晰,一样安全((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)。)就目前而言,我认为没有任何可能性编译器实现符合当今标准的任何其他行为;一种危险是可能为了所谓的“优化”利益而更改标准以破坏行为。
2015年

@supercat:编写该标准的目的是使编译器不必生成其目标处理器自然不支持其行为的代码。出现大多数未定义的行为是因为(在编写标准时)并非所有处理器都表现一致。随着编译器变得越来越成熟,编译器作者开始利用未定义的行为进行更积极的优化。
Bart van Ingen Schenau 2015年

从历史上看,标准的意图主要是您所描述的,尽管标准足够详细地描述了某些行为,以要求某些通用平台的编译器生成比宽松规范所要求的代码更多的代码。类型强制int i=129; signed char c=i;是这种行为之一。相对而言,很少有处理器具有一条指令,当它在-127到+127范围内时,该指令将c相等i,并且会产生其他任何值i到-128到+127范围内的值的任何一致的映射,这些映射不同于二进制补码的减少或。 ..
supercat 2015年

在这种情况下会持续发出信号。由于该标准要求实现要么产生一致的映射,要么一致地发出信号,因此,该标准唯一留有余地以减少二进制补码的空间的平台将是具有饱和算术硬件的DSP。至于“不确定行为”的历史依据,我想说的是问题不仅仅在于硬件平台。即使在溢出会以非常一致的方式运行的平台上,让编译器捕获它也会很有用……
supercat
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.