Topic: Strange behavior on EOF from keyboard.
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/08 Raw View
Consider the following program:
#include <iostream.h>
int
main()
{
streambuf* in = cin.rdbuf() ;
cout.setf( ios::hex , ios::basefield ) ;
while ( in->sgetc() != EOF )
cout << in->sbumpc() << endl ;
cout << in->sgetc() << endl ;
return 0 ;
}
I have just tried this with two different compilers under Solaris 2.5
(Sun CC 4.1 and g++ 2.7.2). When reading from the keyboard, both
manifest the same symptom: the EOF character (^D) must be entered twice
in order for the program to terminate.
Basically, if I understand correctly, the first EOF is not being
memorized; the streambuf::sgetc calls streambuf::underflow both in the
while and after the loop, and each time, a system call to read occurs.
While this is somewhat understandable given the definition of ^D in Unix
(see below), it is definitly NOT what one would expect, given the
behavior of EOF in stdio.
Are both implementations wrong? Or is it normal that reading from a
streambuf behave differently than stdio?
For those not familiar with the Unix keyboard EOF convention: at the
lowest level, there is no keyboard character which will cause an EOF on
the sequential file. Under normal conditions (no special manipulations
to handle single character input), input is line buffered in the OS: a
read will return whenever a newline character is entered, and only when
a newline character is entered or the buffer is full. Entering a ^D
causes the read to return immediately; unlike a newline character, it is
not entered in the buffer. If the ^D is entered as the first character
of a line, this will cause the read system call to return with 0
characters read -- which is also what will happen if you try to read
beyond the end of a normal file. Traditionally, Unix programs treat
this condition as an EOF from the keyboard -- in fact, it requires no
special handling to do so, just act as if you were reading a normal
file. However, this is a one-time thing. The fact that a read was
terminated by a ^D is not memorized in the OS, and the next read will
procede as normal.
In C, stdio memorized the EOF status -- once a read returned 0 bytes
read, the file was stuck at EOF until the state was explicitly cleared
or a seek was done (which, on a keyboard, would change the state from
EOF to error). In istream, the behavior is similar: once ios::failbit
is set, it stays set, and no further input will be attempted. The
problem only occurs when reading directly from streambuf (in fact,
filebuf). In this case, streambuf::sgetc calls filebuf::underflow,
which *always* does a system read.
Again, I'm not really 100% sure of what the correct behavior should be.
Strictly speaking, ^D is NOT an EOF, but simply a trigger for a
particular behavior from the tty driver. And of course, the definition
of EOF from a keyboard is implementation defined, including whether it
even exists. Still, under Unix, this particular behavior is
indistinguishable from EOF on a normal file, at least if the ^D occurs
at the beginning of the line, and has been traditionally used for EOF.
So it would seem that logically, filebuf should memorize the EOF, and
continue returning it. Except: if this solution is adopted, how do you
clear the EOF status?
Typical example: you get EOF, but find errno set to EINTR. This means
that the input was interrupted because of a signal. The normal behavior
is to handle the signal, then clear the EOF, and restart the read.
While all of the programs doing this actually do the input at a lower
level, I would expect the above scenario to work with stdio or
iostream.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]