ferror()

S

Stephen Howe

Hi,

If I attempt to read past the end of a file, feof() will return a non-zero
value. But can I guarantee that ferror() is 0? In short, will the error
indicator be set in some implementations just because the end-of-file
indicator is set? A search on the standard does not reveal if eof is
regarded as an "error" (if does say something, please quote the heading
numbers).

Thanks

Stephen Howe
 
F

Floyd Davidson

Stephen Howe said:
Hi,

If I attempt to read past the end of a file, feof() will return a non-zero
value. But can I guarantee that ferror() is 0? In short, will the error
indicator be set in some implementations just because the end-of-file
indicator is set? A search on the standard does not reveal if eof is
regarded as an "error" (if does say something, please quote the heading
numbers).

There is not much point in using feof(). Whatever function you
use to read data will indicate when an end of file or an i/o
error occurs, for example:

while (fread(..., fp) != 0) {
...
}

When the loop exits, you know positively one or the other
condition has occurred, but generally the the only exception you
want to take is for an error,

if (ferror(fp)) {
... /* handle the error */
}

The program simply continues if no error is indicated, because
the end of file condition is expected.

If an error did occur, it makes no difference if feof() is true
or not.
 
D

Dan Pop

In said:
If I attempt to read past the end of a file, feof() will return a non-zero
value. But can I guarantee that ferror() is 0? In short, will the error
indicator be set in some implementations just because the end-of-file
indicator is set? A search on the standard does not reveal if eof is
regarded as an "error" (if does say something, please quote the heading
numbers).

Having reached the end of file is not considered an error.

OTOH, I can't figure out the practical side of your question. Why do you
need any guarantees about the ferror return value once you have reached
the end of the file?

In practice, reaching the end of file is the most common reason for the
failure of an input function. So, if the input function call returns
a failure indication (EOF or a null pointer), you simply call feof() to
figure out whether it was an eof condition or an I/O error. You don't
need to call ferror() at all in this case.

ferror() is usually useful for output streams, when you don't want to
bother checking each and every output call. If, before calling fclose(),
ferror() returns zero, you can assume that everything was fine up to that
point (if you have performed no actions on that stream that would reset
the stream's error indicator).

Dan
 
G

glen herrmannsfeldt

Dan Pop wrote:

(snip regarding feof() and ferror())
In practice, reaching the end of file is the most common reason for the
failure of an input function. So, if the input function call returns
a failure indication (EOF or a null pointer), you simply call feof() to
figure out whether it was an eof condition or an I/O error. You don't
need to call ferror() at all in this case.
ferror() is usually useful for output streams, when you don't want to
bother checking each and every output call. If, before calling fclose(),
ferror() returns zero, you can assume that everything was fine up to that
point (if you have performed no actions on that stream that would reset
the stream's error indicator).

Shouldn't you also check the return value of fclose()?

I believe that in the case of buffering external to C, all the data
won't necessarily be pushed all the way to the disk, and a disk full
condition could still occur.

I do believe that only a small fraction of programs correctly check
the return status on output files.

-- glen
 
S

Simon Biber

glen herrmannsfeldt said:
Shouldn't you also check the return value of fclose()?

I believe that in the case of buffering external to C, all the
data won't necessarily be pushed all the way to the disk, and
a disk full condition could still occur.

I do believe that only a small fraction of programs correctly
check the return status on output files.

If the fclose function returns an error, which could be due to
disk full, is it reasonable to ask the user to rectify that
condition and then retry the fclose?

ie. something like:
while(fclose(fp))
{
printf("File close failed, press 'r' to retry\n");
if(getchar() != 'r') break;
}

Or is the file pointer invalid after the unsuccessful call?
 
S

Stephen Howe

OTOH, I can't figure out the practical side of your question. Why do you
need any guarantees about the ferror return value once you have reached
the end of the file?

Colleague's code.

He has a function which calls various combinations of fread(), fgetc(),
fgets() and does not bother to inspect the return values.
At the end, he calls ferror() to see if an error occured reading the file
and returns a value from the function if it was "successful" or "not". I am
wondering what happens if the end-of-file is reached whether ferror()
returns 0 or not. I have to say, it intrinsically does not seem to be
robust. I would be testing every call to fread(), fgetc(), fgets() in case
you have an unexpected truncated file.
ferror() is usually useful for output streams, when you don't want to
bother checking each and every output call. If, before calling fclose(),
ferror() returns zero, you can assume that everything was fine up to that
point (if you have performed no actions on that stream that would reset
the stream's error indicator).

Is that enough? It could be that disk space is tight, ferror() indicates no
error yet calling fclose() flushes any buffers in effect and at that point
the C file system suddenly detects there is a problem. You want to flush
first and then see what ferror() returns or alternatively take note of what
fclose() returns.

Stephen Howe
 
T

those who know me have no need of my name

in comp.lang.c i read:
Dan Pop wrote:

Shouldn't you also check the return value of fclose()?

yes, because there may have been buffering of the stream (by default a
stream referencing a file would be block buffered) and the fclose will
flush that data before it closes the underlying interface, and either of
those actions (fflush or underlying_close()) may encounter an error.
 
B

Ben Pfaff

Simon Biber said:
If the fclose function returns an error, which could be due to
disk full, is it reasonable to ask the user to rectify that
condition and then retry the fclose?

No, you must not do that. See the definition in the Standard:

7.19.5.1 The fclose function
Synopsis
1 #include <stdio.h>
int fclose(FILE *stream);
Description

2 A successful call to the fclose function causes the stream
pointed to by stream to be flushed and the associated file
to be closed. Any unwritten buffered data for the stream are
delivered to the host environment to be written to the file;
any unread buffered data are discarded. Whether or not the
^^^^^^^^^^^^^^^^^^
call succeeds, the stream is disassociated from the file and
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
any buffer set by the setbuf or setvbuf function is
disassociated from the stream (and deallocated if it was
automatically allocated).
 
D

Dan Pop

In said:
Dan Pop wrote:

(snip regarding feof() and ferror())



Shouldn't you also check the return value of fclose()?

Have I said or implied otherwise?

Of course you *have* to check it, but this has nothing to do with ferror()
which can no longer be used after the stream has been closed.

Dan
 
G

glen herrmannsfeldt

Dan Pop wrote:
(snip)
Have I said or implied otherwise?

Maybe not, but since you didn't mention it, and since the return value
of fclose() is so rarely checked, I thought it was worth adding to
the discussion.
Of course you *have* to check it, but this has nothing to do with ferror()
which can no longer be used after the stream has been closed.

-- glen
 
A

Alan Balmer

Dan Pop wrote:

(snip regarding feof() and ferror())



Shouldn't you also check the return value of fclose()?
Maybe, but I rarely do. I don't know of any error that would be
recoverable at that point. If the fwrite's have been checked, about
the only thing left is inability to flush the buffers. That's better
detected with an fflush, when you still have ways of correcting the
problem.
 
E

Eric Sosman

Alan said:
Maybe, but I rarely do. I don't know of any error that would be
recoverable at that point. If the fwrite's have been checked, about
the only thing left is inability to flush the buffers. That's better
detected with an fflush, when you still have ways of correcting the
problem.

Even if fflush() succeeds, fclose() can fail.

Whether the fclose() failure is recoverable or not is only
part of the story. You may not be able to do anything about
the error that doomed the fclose(), but you can at least refrain
from making things worse:

stream = fopen("datafile.tmp", "w");
...
fclose (stream);
delete ("datafile.dat");
rename ("datafile.tmp", "datafile.dat");

If the fclose() fails (so the integrity of "datafile.tmp" is
suspect at best), this code merrily clobbers the old and
presumably valid file with the new and possibly broken one.
Better, I think, to detect the fclose() failure, leave both
files intact, and give the user the maximum opportunity to
sort things out.

And yes, this has happened. I've told the tale before
and won't repeat it (go to Google and hunt up the thread
called "reading an Int Array from a Binary file?" if
interested). As for me: Once burned, forever shy.
 
A

Alan Balmer

Even if fflush() succeeds, fclose() can fail.
I don't doubt it, especially in c.l.c. :) However, I can't think of
many such failure modes, and those involve catastrophic hardware
failures. On the implementation I have readily available, any error
condition which is documented for fclose would also be reported on the
fopen, and I suspect that's true of many actual implementations (which
is OT here, of course.)
Whether the fclose() failure is recoverable or not is only
part of the story. You may not be able to do anything about
the error that doomed the fclose(), but you can at least refrain
from making things worse:

The action taken depends on the requirements of the job, the
implementation, the exact error reported, and probably other things,
none of which are standardized. I doubt that there is any standard C
approach to such error recovery which would be very useful.
 
A

Alan Balmer

any error
condition which is documented for fclose would also be reported on the
fopen,

(Reference post above) Ouch! Didn't catch that bit of nonsense until
after downloading the post. Should read "any error condition which is
documented for fclose would also be reported on the fflush, " of
course.
 
C

Chris Torek

Even if fflush() succeeds, fclose() can fail.
[/QUOTE]

I don't doubt it, especially in c.l.c. :) However, I can't think of
many such failure modes, and those involve catastrophic hardware
failures.

It happened in perfectly ordinary "Unixy" code on Sun workstations
using NFS servers, even with all the hardware working perfectly.

Files written to the server would be write-behind cached on the
workstations. On the final fflush()-before-close, the last data
would be transferred from the user process to the client workstation
kernel. The kernel continued to cache the data, not sending any
of it to the NFS server yet.

On the close(), the workstation would realize that it was now
time to send the cached data to the server, which would reject
the write with EDQUOT, "user is over quota".

The close() would return the EDQUOT error to the user process,
alerting the user that his file was incomplete because he was
now out of administrator-assigned disk space.

(This kind of failure generally came as a total shock to the users,
whose programs completely ignored the close() failure and often
followed the failed close() by a rename() operation that wiped
out the original backup file. Now they had plenty of disk space
for the data, but no data to go in it.)
 
D

Dan Pop

In said:
Dan Pop wrote:
(snip)



Maybe not, but since you didn't mention it, and since the return value
of fclose() is so rarely checked, ^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How do you know?
I thought it was worth adding to the discussion.

Huh? Has it anything whatsoever to do with ferror, which is the topic
of this discussion?

Dan
 
S

Stephen Howe

Right. In general, pay attention to the return value of fclose()
particularly if the file is opened for writing.

Stephen Howe
 
D

Dan Pop

In said:
Maybe, but I rarely do. I don't know of any error that would be
recoverable at that point. If the fwrite's have been checked, about
the only thing left is inability to flush the buffers. That's better
detected with an fflush,

All fflush can tell you is that the data has successfully left the
stdio buffers. It may still be bufferred by the OS. Only fclose can
confirm that it successfully reached its final destination.
when you still have ways of correcting the problem.

Even if it's not recoverable, the user still needs to be informed about
the problem. As it is impossible to predict the consequences of a
failed fclose, it is unacceptable to ignore this possibility.

Dan
 
D

Dan Pop

In said:
(Reference post above) Ouch! Didn't catch that bit of nonsense until
after downloading the post. Should read "any error condition which is
documented for fclose would also be reported on the fflush, " of
course.

Chapter and verse, please.

Dan
 
D

Dan Pop

In said:
Right. In general, pay attention to the return value of fclose()
particularly if the file is opened for writing.

If it's opened for input only, you couldn't/shouldn't care less.

Dan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,794
Messages
2,569,641
Members
45,355
Latest member
SJLChristi

Latest Threads

Top