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