[net.lang.c] Why gripes about C enums should be taken in context

swatt (11/10/82)

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

mark (11/10/82)

Alan forgot to mention the single most important addition to C
since V6: #include with <> brackets!

In V6, there was no /usr/include, and of course, no /usr/include/sys.
All system calls which dealt with structures contained the text of
the structure in the manual page, and programs were expected to copy
the structure declation into their program.  Thus, all hope of being
portable to any machine except a PDP-11 was gone.  Only when the
#include <xx.h> convention started to take hold did UNIX begin to
become portable.  (I suppose rewriting it in C was another major
step in that direction, too.)

This, of course, implies that there was no standard I/O.  With no
<stdio.h>, all I/O was done with putchar and printf (which always
went to stdout) and getchar, which always read from stdin.  (There
was a way to divert this to another file descriptor, which even
the programmers manual called a "kludge".)  There was a putc/getc
package that required you to declare a 518 byte buffer (not a structure
with a 512 byte char array, two pointers, and an integer, mind you,
but a 518 byte buffer!) and implemented essentially fopen, putc,
getc, and fclose (but this could not be used with printf, and there
was no scanf.)  There was something called the "portable C library"
which implemented printf, fprintf, and sprintf with one routine
called printf, like this:
	printf("format", args);		/* printf */
	printf(fd, "format", args);	/* fprintf */
	printf(-1, buf, "format", args);/* sprintf */
The portable C library didn't get used much - it was inefficient,
and not especially robust.

We've really come a long way!  Of course, it's been six years since
V6 was released, and no doubt longer since it was packaged.  six
years is half the lifetime of UNIX and 1/5th the lifetime of the
entire Computer Science field.

ecn-pa:bruner (11/11/82)

Ah, fond memories of days gone by.  The most significant thing that
I remember about V6 C was:

	Not only was there no "long" (or "short" for that matter)
	but there was no "unsigned".  A common method of obtaining
	an unsigned integer was to use a pointer to character.
	Pointers were often considered to be equivalent to integers.
	(At least, many programs used them interchangeably.  There
	were no type casts at that time.)

I remember first reading about C in the Beginner's Guide to UNIX(tm)
and how wonderful it was supposed to be.  I was pretty skeptical
of these claims until I had written my first couple of programs.
After that it was C all the way.

--John Bruner
  Purdue/EE

CSvax:cak (11/13/82)

Alan,

Under v6, I seem to recall that you could use longs as long
as you just wanted to add and subtract (and maybe mod). The other
math support routines apparently didn't get written in time
to make the tape as it was hurrying out the door. I believe that
most of the type conversion routines were missing, too.

Amazing as it may seem, there are folks on campus here who still
run v6; so I occasionally get source files with that stupid #
by itself on the first line....

(How did we ever live without structure assignment?)

Cheers,
chris

jfw (11/18/82)

I saw this message which mentioned something about lots of people still used
to V6 causing the # character to be on a line by itself at the top/

What is the meaning of a # character all by itself?  What meaning did it have
in V6 that it appears to have lost since?

John Woods
...mitccc!jfw