Why gripes about C enums should be taken in context
utzoo!decvax!ittvax!swatt
utzoo!decvax!ittvax!swatt
Wed Nov 10 11:38:24 AEST 1982
I thought it might benefit some readers to look at what they're missing
by using the current C language, and also to try to recapture in my
rapidly fading memory what it was like when I first ran into it.
(Think of this as "net.lang.c.nostalgia")
I'm sure some other C old-timers could go back even farther than
V6 with some amusing anecdotes.
I won't attempt to give a complete description, but here are some
differences between the current language (at least V7 release), and
the first version I saw on V6:
cpp:
Instead of running as a separate pass, the pre-processor
function was imbedded in the "cc" driver program. The first
character in your C source had to be a '#' if you intended to
use any preprocessor functions, otherwise "cc" would just start
up the first pass directly on the source.
No macros with parmeters.
No "#if EXPRESSION". I think, but I could be wrong, that
there was no "#else" either. Basically, all you got was:
"#define", "#undef", "#ifdef", "#ifndef", and "#endif".
cc:
No unions, typedefs, type casts. No function parameters
declared as register variables. Error if you declared
more than 3 register variables. No top level "static"
storage class (private to a file). No variable declarations
inside compound statements.
Zero checking that structure members were actually used
in an expression of type structure or pointer to structure.
The following was common:
struct {
char lobyte, hibyte;
};
int junk;
int *ip;
junk.lobyte = 'c'; junk.hibyte = '\0';
ip = &junk; ip->lobyte = 'q';
Speaking of characters, there was also a "long" character
constant:
int junk;
junk = 'xy';
No initialization of variables declared local to a function.
External initialization had some glitches:
struct {
char label[8];
float fnum;
int inum;
} junk[] ={
"string", /* This wouldn't align properly,
* but I can't remember why.
*/
3.1412, /* This actually took up space
* for a type "double", not "float".
*/
...
};
I don't remember what the problem with strings was; I just
remember you never declared members of initialized structures
as character arrays -- you declared them as pointers instead
and it all worked.
No support for type "long" !!! I think the compiler recognized
the type name, but barfed on generating code.
And of course, none of the even newer features of the language:
structure and union assignment, enumerated types.
Ah, yes, I almost forgot, there was a notion of a "label variable",
which could be used to do non-local gotos:
int (*labelp)();
again:
...
again1:
...
if (expr)
labelp = again;
else labelp = again1;
goto lablep;
What was most fun about this one is you could set the pointer
to anything, and just go there:
int jail() {}
main (){
int (*lp)();
lp = jail;
goto lp;
}
That got you directly to "jail" without all the muss and fuss
of procedure-call linkage. Of course, getting back out was apt
to be a bit sticky ...
One last one: "sparse" switch statements were not re-entrant:
func(c) {
switch (c) {
case 1:
case 2:
case 3:
<stuff ... >
case 1000:
case 1001:
case 2048:
return (func (c));
default:
<stuff ...>
}
}
This was unsafe, as the value being switched on was stored
an an external cell that was part of the switch table.
Well, that ought to be enough. Anyone else out there got some gems
they'd like to share?
- Alan S. Watt
More information about the Comp.lang.c
mailing list