为什么 ::feof() 与 ::_eof(::fileno()) 不同?

发布于 2024-12-25 21:24:26 字数 1204 浏览 0 评论 0原文

免责声明:请勿使用 ::feof() 作为循环条件。例如,请参阅以下答案:文件读取:二进制文件的 feof()

但是,我有“真实”代码演示了一个不使用的问题::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。)

DISCLAIMER: Don't use ::feof() as your loop condition. For example, see the answer to: file reading: feof() for binary files

However, I have "real" code that demonstrates a problem that does not use ::feof() as my loop condition, but LOGICALLY, this is the easiest way to demonstrate the problem.

Consider the following: We iterate a character stream one-at-a-time:

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"
}

The above code works as expected: The file is processed one-char-at-a-time, and upon EOF, we drop out.

HOWEVER, the following has unexpected behavior:

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"
}

I would have expected them to perform the same. ::fileno() properly returns the (integer) file descriptor every time. However, the test ::_eof(::fileno(my_file)) works exactly once, and then returns 1 (indicating an EOF) on the second attempt.

I do not understand this.

I suppose it is conceivable that ::feof() is "buffered" (so it works correctly) while ::_eof() is "un-buffered" and thinks the whole file is "read-in" already (because the whole file would have fit into the first block read in from disk). However, that can't possibly be true given the purpose of those functions. So, I'm really at a loss.

What's going on?

(Files are opened as "text", are ASCII text files with about a dozen lines, MSVS2008, Win7/64.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如若梦似彩虹 2025-01-01 21:24:26

我认为 ::feof() 是“缓冲的”(所以它可以工作
正确)而 ::_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);

  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 处理文件流时。

I suppose it is conceivable that ::feof() is "buffered" (so it works
correctly) while ::_eof() is "un-buffered" and thinks the whole file
is "read-in" already (because the whole file would have fit into the
first block read in from disk). However, that can't possibly be true
given the purpose of those functions. So, I'm really at a loss.

I don't know why you would think it "can't possibly be true given the purpose of those functions." The 2 functions are meant to operate on files that are opened and operated on in different ways, so they are not compatible.

In fact, that is exactly what is happening. Try this:

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"
}

I will try to elaborate a bit based on your comment.

When you call fopen, you are getting back a pointer to a file stream. The underlying stream object keeps it's own file pointer which is separate from the actual file pointer associated with the underlying file descriptor.

When you call _eof you are asking if you have reached the end of the actual file. When you call feof, you are asking if you have reached the end of the file stream. Since file streams are usually buffered, the end of the file is reached before the end of the stream.

I'm still trying to understand your answer below, and what the purpose
is for _eof() if it always returns 1 even when you didn't read
anything (after the first char).

To answer this question, the purpose of _eof is to determine if you have reached the end of the file when using _open and _read to work directly with file descriptors, not when you use fopen and fread or getc to work with file streams.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文