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