免责声明:请勿使用::feof()作为循环条件。例如,请参见以下答案:file reading: feof() for binary files

但是,我有“真实的”代码演示了一个不使用::feof()作为循环条件的问题,但从逻辑上讲,这是演示该问题的最简单方法。

请考虑以下因素:我们一次迭代一个字符流:

FILE* my_file;
// ...open "my_file" for reading...

int c;
while(0 == ::feof(my_file))
{ // We are not at EOF
  c = ::getc(my_file);
  // ...process "c"
}


上面的代码按预期方式工作:一次处理一个字符的文件,然后在EOF上退出。

但是,以下内容具有意外的行为:

FILE* my_file;
// ...open "my_file" for reading...

int c;
while(0 == ::_eof(::fileno(my_file)))
{ // We are not at EOF
  c = ::getc(my_file);
  // ...process "c"
}


我希望他们能执行相同的操作。 ::fileno()每次都正确返回(整数)文件描述符。但是,测试::_eof(::fileno(my_file))仅工作一次,然后在第二次尝试时返回1(指示EOF)。

我不明白。

我想可以想象::feof()是“缓冲的”(因此它可以正常工作),而::_eof()是“未缓冲的”,并且认为整个文件已经“读入”(因为整个文件适合从磁盘读入的第一个块)。但是,鉴于这些功能的目的,这不可能是正确的。所以,我真的很茫然。

这是怎么回事?

(文件以“文本”形式打开,是大约十二行的ASCII文本文件,MSVS2008,Win7 / 64。)

最佳答案

我想可以想象:: feof()是“缓冲的”(因此它可以工作
  正确),而:: _ eof()是“未缓冲的”,并且认为整个文件
  已被“读入”(因为整个文件将适合
  从磁盘读取的第一个块)。但是,那不可能是真的
  给出这些功能的目的。所以,我真的很茫然。


我不知道您为什么会认为“鉴于这些功能的目的,它不可能是正确的”。这2个功能旨在对以不同方式打开和操作的文件进行操作,因此它们不兼容。

实际上,这正是正在发生的事情。尝试这个:

FILE* my_file;
// ...open "my_file" for reading...

int c;
while(0 == ::_eof(::fileno(my_file)))
{ // We are not at EOF
  c = ::getc(my_file);

  long offset1 = ftell(my_file);
  long offset2 = _tell(fileno(my_file));

  if (offset1 != offset2)
  {
     //here you will see that the file pointers are different
     //which means that _eof and feof will fire true under different conditions
  }
  // ...process "c"
}


我将根据您的评论尝试详细说明。

调用fopen时,您将获得指向文件流的指针。基础流对象保留其自己的文件指针,该文件指针与与基础文件描述符关联的实际文件指针分开。

调用_eof时,您正在询问是否已到达实际文件的末尾。调用feof时,您正在询问是否已到达文件流的末尾。由于通常会缓冲文件流,因此文件的末尾要早于流的末尾。


  我仍在尝试了解您在下面的回答以及目的
  是_eof()的代码,即使即使您没有阅读它也始终返回1
  任何东西(在第一个字符之后)。


为了回答这个问题,_eof的目的是确定使用_open和_read直接使用文件描述符时是否到达文件末尾,而不是使用fopen和fread或getc处理文件流时是否到达文件末尾。

关于c++ - 为什么:: feof()与:: _ eof(:: fileno())不同?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8783499/

10-09 02:11