When fopen() fails

D

Dan Pop

In said:
There are no semantic differences, but "zero" would be clearer.

If there are no semantic differences, both are equally clear, considering
that both "null" and "zero" are common English words.
The
word "null" is commonly used to refer to certain pointer values (NULL)
and character values ((char)'\0'), but rarely used to refer to a zero
integer value.

"Null pointer", "null pointer constant" and "null character" are all
concepts defined by the C standard. They don't monopolise the usage of
the word "null" any more than "floating point" and "decimal point"
monopolise the usage of the word "point".
The phrase "errno is non-null" isn't incorrect, it's
just an odd way of putting it.

If I saw anything odd about it, I wouldn't have used it in the first
place. And this is not an English language issue (and myself being a
non-native English speaker); it's exactly the same in my native language
(except that "null" is spelled with a single ell :)
It's really not a big deal.

An excellent reason for NOT ignoring it in c.l.c ;-)

Dan
 
D

Dan Pop

In said:
If a function does not communicate an error via errno, it is allowed
to set errno to any value it wants (except zero).
If a function communicates errors though errno, it is required either
to set errno to an error value, or to leave errno with the same value
as before the call.

Please correct me if that's not right.

Use the following simple model: the value of errno may be meaningful
after a *failed* function call only if it was reset before the call
and it is non-zero after the (failed) function call.

The standard guarantees that for a restricted set of library functions,
but a good implementation should use errno whenever there is no other
way of telling why a function failed. E.g. if getc fails, you can use
ferror() and feof() to distinguish between an I/O error condition and an
end of file condition, but when fopen fails, *only* errno can provide a
clue.

The value of errno is useless in any other scenario (all we know about it
is that it is guaranteed to be 0 when the program execution begins and
that no standard library function resets it).

Dan
 
S

S.Tobias

[Thanks to Eric Sosman - while writing the above I was thinking in context
of a failed call, but of course I wasn't clear about it. Anyway good
you added more explanation.]
Use the following simple model: the value of errno may be meaningful
after a *failed* function call only if it was reset before the call
and it is non-zero after the (failed) function call.

....and provided that the function is actually errno-setting; otherwise
it's meaningless again, which makes portable programming very hard.
I have very bad feelings about errno:
errno = 0;
if (!fopen(..))
#if fopen_is_errno_setting
perror("fopen()");
#else
fputs("fopen() failed\n", stderr);
#endif
The standard guarantees that for a restricted set of library functions,
but a good implementation should use errno whenever there is no other
way of telling why a function failed. E.g. if getc fails, you can use
ferror() and feof() to distinguish between an I/O error condition and an
end of file condition, but when fopen fails, *only* errno can provide a
clue.

I think it's not entirely correct (non-)analogy. fopen() always returns
NULL when it fails, so we do know an error situation has arisen, but
errno can give us more information on the *nature* of the error. getc()
returns NULL on error or on end-of-file (which I don't consider an error
condition, but tastes may vary), and ferror() can distinguish between
the two. But here we don't have any information as to the nature of
the error, because getc() does not set errno.
The value of errno is useless in any other scenario (all we know about it
is that it is guaranteed to be 0 when the program execution begins and
that no standard library function resets it).

Is it a good idea for a user function to communicate its own errors
through errno? Could additional E.. macros from errno.h have negative
values (the Std doesn't seem to restrict this, but I haven't met a
system where this would be true)?
 
E

Eric Sosman

S.Tobias said:
Is it a good idea for a user function to communicate its own errors
through errno? Could additional E.. macros from errno.h have negative
values (the Std doesn't seem to restrict this, but I haven't met a
system where this would be true)?

Not a good idea, I think. The immediate practical
difficulty is in getting perror() and strerror() to
recognize the application-defined values; the Standard
provides no way to do this.
 
R

Richard Bos

pete said:
A null pointer will compare equal to zero, that's one way.

No, it won't. It will compare to a _source_ zero, because that's also a
null pointer constant, but that's a special property of the null pointer
constant, _not_ of the null pointer object. It need not, for example,
compare equal to an integer object with value zero.
I meant "integer", as in "integer type".

I realised that, I just thought I'd point it out explicitly for the
lurkers.

Richard
 
D

Dan Pop

In said:
...and provided that the function is actually errno-setting; otherwise
it's meaningless again, which makes portable programming very hard.
I have very bad feelings about errno:
errno = 0;
if (!fopen(..))
#if fopen_is_errno_setting
perror("fopen()");
#else
fputs("fopen() failed\n", stderr);
#endif

It's a quality of implementation issue. A good implementation of a
standard library function either sets errno to a meaningful value
upon failure or preserves its value. So, my approach is likely to work
quite well, even if the standard doesn't guarantee it.

If you don't want to rely on it, you're restricted to the two errno
values of C89 or three errno values of C99 and you won't be able to tell
the user why fopen() failed, because you have no portable way of telling
whether fopen sets errno to meaningful values or not.
I think it's not entirely correct (non-)analogy. fopen() always returns
NULL when it fails, so we do know an error situation has arisen, but
errno can give us more information on the *nature* of the error. getc()
returns NULL on error or on end-of-file (which I don't consider an error
condition, but tastes may vary), and ferror() can distinguish between
the two. But here we don't have any information as to the nature of
the error, because getc() does not set errno.

Huh? There are exactly two things that can go wrong: an I/O error and
an eof condition. Neither the programmer nor the user needs to know more
than that.
Is it a good idea for a user function to communicate its own errors
through errno? Could additional E.. macros from errno.h have negative
values (the Std doesn't seem to restrict this, but I haven't met a
system where this would be true)?

Macros that begin with E and a digit or E and an uppercase letter are in
the implementation name space and can't be defined by portable programs.

And errno itself, without perror and strerror is not of much use to the
application programmer. For other libraries, it's much safer to
replace errno by lib_errno and provide lib_perror and lib_strerror.

The issue was discussed, at great length, 1 year or 18 months ago, in the
context of the comp.lang.c library project. The project died when its
main advocates realised that they can't do as much as they intended
within the constraints of the C standard (mainly, they felt that a library
that is not thread-safe is not of much use to them and thread-safety
cannot be achieved in portable C code).

Dan
 
S

S.Tobias

Dan Pop said:
[snip]
I have very bad feelings about errno:
errno = 0;
if (!fopen(..))
#if fopen_is_errno_setting
perror("fopen()");
#else
fputs("fopen() failed\n", stderr);
#endif
[snip]
If you don't want to rely on it, you're restricted to the two errno
values of C89 or three errno values of C99 and you won't be able to tell
the user why fopen() failed, because you have no portable way of telling
whether fopen sets errno to meaningful values or not.

I only think that errno handling is badly designed by the Standard.
The Standard allows to introduce extensions here, but in a very unfriendly
way. In theory, on every new implementation I want to port to, I have
to check *each* function whether it is errno-setting, otherwise I might
get unrelated error messages. OTOH nothing vital should depend on perror()
and errno (in general). I consider it more like a debugging feature.

^^^^
Failing getc() (ferror() set) doesn't give any more or less clue than
a NULL from fopen(). errno could be/is auxiliary feature for both.
Huh? There are exactly two things that can go wrong: an I/O error and
an eof condition. Neither the programmer nor the user needs to know more
than that.

You can apply similar argument to fopen().


In the past I worked a little with Berkeley DB. All functions returned
error status (zero for no error). IIRC positive values were system
errors (from errno.h), low negative values were reserved for the library
errors (it supplied its own strerror()), and high negative numbers
(nearer zero) were reserved for user errors. I have started to
wonder how "safe" is the assumption that with this scheme we won't
step onto an implementation's E.. values. (I have checked - even
SUS3 doesn't (explicitly) require all E.. numbers be positive).
 
D

Dan Pop

In said:
^^^^
Failing getc() (ferror() set) doesn't give any more or less clue than
a NULL from fopen().

Nonsense. ferror() set after a failed getc call means an I/O error
occurred, while an I/O error is only *one* of the many reasons fopen
can fail.
errno could be/is auxiliary feature for both.

The average user couldn't care less about the exact nature of the I/O
error. When such information is needed, there are other, *much*
better ways of retrieving it (system logging facilities). What errno
setting should correspond to "bad CRC on sector 1234233 on disk 08:01"?
You can apply similar argument to fopen().

Nope: an I/O error is only one of the many reasons fopen can fail.
No similarity in sight.

Dan
 
S

S.Tobias

Nonsense. ferror() set after a failed getc call means an I/O error
occurred, while an I/O error is only *one* of the many reasons fopen
can fail.

All right. I was paying more attention to the general idea rather than
to the particular function I was talking about. Perhaps fputc() is
more amenable to the discussion. Most previous arguments apply to it,
except it does not set feof() of course.

GNU man pages don't mention that fputc() sets errno, but SUS3 does.
Looking at the list of errors, I think that differentiating between
EIO, EFBIG and ENOSPC might be important to the user.

Looking at the analogous list for fgetc(), there are less errors
that a user might be interested in, but it definitely shows that
I/O errors are *not* the only reasons for fgetc() failure (ENOMEM,
EINTR, EBADF).

I would see nothing wrong if on some implementaton getc() could fail
and set errno to ETEA, where strerror(ETEA) returned:
"it's after 5pm, CPU is having tea-time, be back in 20 minutes"

[snip]
Nope: an I/O error is only one of the many reasons fopen can fail.
No similarity in sight.

I agree that errno from fopen() is much more valuable and informative
to the user. I can do without, so I usually don't care about it.


I really wouldn't like to spark a long discussion on this. My remark
was just meant to be about analogies on a more abstract-like level
rather than practical.
 

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

Similar Threads

fopen 20
Working with files 1
fopen 17
fopen question 7
Problem with fopen 13
fopen() questions 17
HELP:function at c returning (null) 4
PHP failed to create file 13

Members online

Forum statistics

Threads
474,147
Messages
2,570,835
Members
47,383
Latest member
EzraGiffor

Latest Threads

Top