Random832 said:
The standard requires some things that are utterly pointless. Requiring
that stdin/stdout/stderr are macros is one of these. Requiring that FILE
be a complete type is another.
Useless for modern programs, yes.
But, utterly pointless, no.
The standard specifies such things for compatibility with legacy code.
Probably small amounts of legacy code. But, since it doesn't harm,
maintaining backward compatibility is a good thing.
For stdin, stdout and stderr, requiring that they be macros (instead of
simply allowing it) allow some programs to do things such as:
#include <stdio.h>
#undef stdin
#define stdin my_stdin
If the standard had specified that stdin can be a macro but is not
guaranteed to be one, an easy workaround would have been:
#include <stdio.h>
#ifdef stdin
#undef stdin
#endif
#define stdin my_stdin
But it would have broken legacy code.... Plus, it simplifies a bit more
modern programs that want to #undef stdin... And it avoids that, guys
who doesn't know well the standard, accidentally write non-portable
code, relying on the fact that their particular compiler define stdin
as a macro.
Such code does exist:
http://www.google.com/codesearch?hl=en&q=#undef\+stdin$
The fact that FILE has to be a complete type, is probably used in
legacy code for things like:
FILE Special; /* won't be initialized to anything particular, but that
doesn't matter */
/* this FILE is only designed to have an address distinct from all
addresses of real FILE structures */
void Function(FILE* f) {
if (f==&Special) {
/* handle this case specially */
}
}
/* invocation examples */
Function(stdout);
Function(NULL); /* does another thing */
Function(&Special); /* again, treated differently */
This programming style is *very* ugly, yet the standard doesn't want to
break gratuitously legacy code, even when it has very bad style.
Of course, FILE being a complete type, doesn't implies that it can't be
opaque.
The definition of FILE may be:
typedef struct {char __dummy;} FILE;
Note: If getc is implemented as a macro, it may use a typecast from
FILE* to _FILE* where _FILE is a complete type containing the real
fields used by the compiler internally.
It won't really hide the structure from malicious programmers, but it
will prevent the innocent programmer from accidentally accessing fields.