为什么 ::feof() 与 ::_eof(::fileno()) 不同?
免责声明:请勿使用 ::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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不知道为什么你会认为“考虑到这些函数的目的,这不可能是真的”。这两个函数旨在对以不同方式打开和操作的文件进行操作,因此它们不兼容。
事实上,这正是正在发生的事情。试试这个:
我会根据您的评论尝试详细说明一下。
当您调用 fopen 时,您将返回一个指向文件流的指针。底层流对象保留它自己的文件指针,该指针与与底层文件描述符关联的实际文件指针是分开的。
当您调用 _eof 时,您会询问是否已到达实际文件的末尾。当您调用 feof 时,您是在询问是否已到达文件流的末尾。由于文件流通常是缓冲的,因此在流结束之前就到达了文件末尾。
要回答这个问题,_eof 的目的是确定当使用 _open 和 _read 直接处理文件描述符时是否已到达文件末尾,而不是当您使用 fopen 和 fread 或 getc 处理文件流时。
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:
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.
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.