In article <11************ **********@l77g 2000hsb.googleg roups.com>
Bill Pursell <bi**********@g mail.comwrote (in part):
fp = fopen( filename , "w" );
if( fp == NULL ) {
fprintf( stderr, "Error opening %s. ",
filename );
perror( "Most recent system error" );
...
>(I think it was Chris Dollin who suggested the
"most recent system error" type message.)
Actually, it was probably me.
There is a danger in the above code: the call to fprintf() may
change errno, and in fact, on at least one common system (4.2BSD
Unix), it *did* do so. If you have ever had email returned with
the error string "Not a typewriter" included, this is exactly why:
the mail delivery agent attempted some operation that failed and
set errno appropriately; then it printed something to stderr, which
changed errno to ENOTTY; then it called perror(), which printed
"Not a typewriter".
The trick is to capture the "errno" "global variable" before it
can change. The easiest way to do that is to use strerror(errno)
in the fprintf() call, so that the string for fprintf() is computed
before fprintf() has a chance to overwrite errno.
(You can of course save and restore errno around the fprintf().
In fact, this is how I fixed the problem in the C library in 4.4BSD:
the setup routine that fprintf() calls, which modifies errno, saves
and restores errno so as to prevent this kind of disturbance. This
fix went in some time before 4.3-net-2, so it is in all modern BSD
systems. Older systems, including at least some Solaris systems,
however, have the "fprintf overwrites errno" bug. Note that only
the *first* fprintf to any particular stream does this -- if you
print something to stderr early on, a later fprintf(stderr) leaves
errno unchanged.)
(For the especially-curious: the reason for this is that stdio must
determine, at runtime, whether a given stream is talking to an
"interactiv e device", in which case the output is to be line buffered
rather than fully buffered. To find out, stdio executes an ioctl()
operation that fails with ENOTTY if the output stream is connected
to a "non-tty" device. If the ioctl succeeds, the stream's "line
buffered mode" flag is set. In this case, the ioctl() call does
not change errno. This means the errno disturbance never actually
happens when running a program "interactively" , making it even more
interesting to debug. "./prog >& errs" produces the problem, but
"./prog" does not.
It would be possible to avoid the "interactiv e device" test on
stderr, which is never fully-buffered in the first place, but for
various reasons I, and presumably whoever had a hand in the earlier,
4.2BSD stdio as well, did the test anyway. In my case, I wanted
to obtain other information at the same time.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.