int sgetc ( );
Now if it returns a char why could we not have it as char sgetc( ) ?
Because it has to return out of band information. The return
value is either in the range [0, UCHAR_MAX], or is EOF
(guaranteed to be negative, typically -1).
I posted about this in c.s.c++ a few days ago but
the post seems not to have shown up...
I couldn't find where in the standard it specifies
that sgetc() returns stuff in that range, the
standard only seemed to have circular references.
Interesting. You could easily be right with regards to
streambuf itself; I can't remember having seen this explicit
constraint myself, either. What is required, however, is that
char_traits<char>::eof() return EOF (which is defined in the C
standard, and must be negative), and that eof() be
distinguishable from any valid char value converted to an int.
Without looking at it in detail: the semantics of filebuf are
defined in terms of the semantics of FILE*, as defined in the C
standard; the requirements that I mentionned are in fact those
of fgetc(), in the C standard. So I'd say that the intent, at
least is clear.
Note that it is difficult to say much, at a standards level,
because even in C, you have the difficulty that when assigning
the results of fgetc() to a char, "either the result is
implementation-defined or an implementation-defined signal is
raised." Any implementation which raises a signal here is going
to break 99.99% of all C code ever written.
The real solution is simple, of course: require plain char to be
unsigned. The problem is that plain char was signed on a PDP-11
(because making it unsigned resulted in a significant
performance hit), and a lot of early C was written supposing
that char was signed. Vendors of C compilers didn't want to
break this code (even if K&R said that it was already broken),
so even today, C and C++ allow plain char to be signed, and most
compilers make it signed by default. And would continue to do
so, even if the standard said that it had to be unsigned.
C++ could solve the problem, theoretically, by requiring
char_traits<char>::to_char_type to do the right thing, even if
the conversion int->char could raise a signal---in fact, I
rather suspect that that is the intent even today. But
practically, who uses char_traits<char>::to_char_type to convert
an int to a char, except maybe in a template, where you're
concerned about instantiations other than char?
That code is wrong on several counts, and fails on a lot of
common implementations. (VC++ under Windows, g++ under Linux on
a PC, g++ or Sun CC under Solaris, etc.) Just for the fun of it,
try compiling it with the option /J with VC++, or
-fno-signed-char with g++. (At least g++ gives a warning.) With
signed char, try it with a list of the towns in the Paris
suburbs. If you're using ISO 8869-1 (a frequent default),
you'll probably find that it stops in the middle of
L'Haÿ-les-Roses.
Of course, if the goal is to copy any file, it also fails
because it doesn't open the files in binary mode, so some byte
values (0x1A under Windows, for example), won't be readable, and
others might be translated in some funny ways (Windows will
insert a 0x0D in front of any 0x0A output, even if there wasn't
one in the input). There's also no error checking, of course.
The program returns a successful status even if the disk was
full, and the copy was incomplete.
These last two issues may have simply been ignored for
pedagogical reasons, however (although if this is the case, a
short sentence saying so would be appreciated). But the use of
out of band data here is fundamental to the C/C++ idiom of
character IO, and cannot be ignored.