[net.lang.c] What happened to labels

cottrell@NBS-VMS.ARPA (COTTRELL, JAMES) (03/01/86)

/*
> I recall that C on early UNIX's treated labels as constants of type
> (int *).  As a result, you could assign labels to variables and even
> jump to the label in a variable.  This got taken out of K&R, and
> as I far as I can tell it's not in other C's today.
> 
> This is unfortunate; 

I don't think you will get much sympathy on this point.

> I ran into a situation recently in which I wanted
> to (automatically) generate C code that should, for efficiency reasons,
> contain label variables.  I had to simulate them with a switch statement
> of the form:
> 
> 	switch(labelindex) {
> 		case 1: goto label1;
> 		case 2: goto label2;
> 		...
> 		case n: goto labeln;
> 		default: fprintf(stderr,"unknown label index: %d\n",
> 					labelindex);
> 			 abort();
> 	}

 	switch(labelindex) {
 		case 1: label1: <code> break;
 		case 2: label2: <code> break;
 		...
 		case n: labeln:	<code> break;
 		default: fprintf(stderr,"unknown label index: %d\n",
 					labelindex);
 			 abort();
 	}

 
> This is a lot slower, though, and some of the compiler's I tried it
> on (the VAX VMS C compiler, for example) did not peephole optimize the
> jump table implementing the switch and the branch instructions
> implementing the goto's (this should have been treated as a jump
> to a jump).
> 
> I'm curious if any commerically available C compilers implement jumps
> to arbitrary pointers without recourse to assembly language inserts.

Probably not. I think they all wised up. Why don't you?

	jim		cottrell@nbs
*/
------

herndon@umn-cs.UUCP (03/10/86)

  [Gobble!]

  Ad-hominem arguments prove little.  Mr. Dietz (Dr. Paul Dietz?)
mentioned a problem to which he found an elegant solution in a
now unsupported feature of C.  I too have had similar problems and
think the statement to 'wise up' is very short-sighted.  Many
persons are capable of independent, creative thought and conjure
up elegant solutions to difficult problems.  These solutions often
violate common standards of 'structured programming'.  As classic
essays and novels often violate the standards of 'good english',
the most important thing about a program is not that it observe
the standards of 'structured programming'.  Manuals of style such
as 'The Elements of Style' by Strunk & White and 'The Elements of
Programming Style' by Kernighan & Plauger make this clear.
  A program, like prose, should convey its meaning to both the
machine and the programmer in the most direct and comprehensible
way possible.  This is not always best done by observing the strict
guidelines of structured programming.  On rare occasions, goto's
are the most elegant way to do things.  I will readily admit that
these situations are uncommon.
  The reasons usually given for avoiding the use of goto's in
computer programs are well-known.  These reasons are quite powerful,
and I strongly believe in them.  However, if a programmer were to
argue that "All labels are bad, so we should remove them from all
languages, including assembly code", we would think him ignorant.
  The C programming language used to permit arbitrary goto/label
operations through carelessness with types -- a label was simply
another value like an integer or pointer and could be manipulated
as such.  As C has acquired such add-ons as 'unions', type-coercion
operators, and stronger typing, a possibly useful operation has been
lost -- quite probably through carelessness.  Like the type 'void'
which was added as an afterthought and has bugs (try declaring
pointers to functions which return 'void' sometime with some of the
common compilers), the absolute restrictions laid down on label
usage also may be hasty.
  When C started acquiring stricter types, no special label type
was included for coercions or any other operations.  Thus one
cannot fill an array with labels to construct a jump table (even
though this can not cause any type conflicts) nor can one have
a variable of type label.  Constraints that all variables of
type label be initialized to a legitimate label, and that such
variables must be local and may not be passed as parameters might
cover the problems of goto's going to undefined locations.  Jump
tables are quite useful to those of us who write programs to
generate C programs -- and we might happily observe such constraints.
  I am sorry to write so much.  However, I think that C's restrictions
on labels have done little to stop the potential abuse of labels,
and has severely hampered those of us who would use them in an
organized and methodical fashion.  I would be gratified if the C
standards committee were to think over the present restrictions on
labels very carefully.

				Robert Herndon
				...!ihnp4!umn-cs!herndon
				herndon.umn-cs@csnet-relay.ARPA
				Dept. of Computer Science,
				Univ. of Minnesota,
				136 Lind Hall, 207 Church St. SE
				Minneapolis, MN  55455

kwh@bentley.UUCP (KW Heuer) (03/15/86)

In article <1700005@umn-cs.UUCP> umn-cs!herndon writes:
>  When C started acquiring stricter types, no special label type
>was included for coercions or any other operations.  Thus one
>cannot fill an array with labels to construct a jump table (even
>though this can not cause any type conflicts) nor can one have
>a variable of type label.  Constraints that all variables of
>type label be initialized to a legitimate label, and that such
>variables must be local and may not be passed as parameters might
>cover the problems of goto's going to undefined locations.  Jump
>tables are quite useful to those of us who write programs to
>generate C programs -- and we might happily observe such constraints.

It would be more in the "spirit of C" to not enforce those restrictions,
and let a branch to anything other than a label in the current function
be an undefined result.  This might be useful for sufficiently esoteric
applications (under #ifdef, of course), and lint might be able to catch
the violations.

I think someone already said how to simulate arrays of label pointers,
but let's be explicit here.  I assume that the only legal operations
on a label are branch and address-of, just as with a function.  So we
can take any program that uses labels and replace the type "label *"
(plain "label" is as useless as plain function, "void ()") with the
datatype "enum label", and replace any label constants x (other than in
goto statements) with LAB_x.  Define enum label to contain all such
LAB_x.

Now if p was of type "label *" (so it is now a "enum label"), replace
"goto *p" with "switch (p) { case LAB_x: goto x; ... }".  Note that p
can be any expression.

I would hope that any good optimizer would convert the switch into a
jump table; there is some inefficiency introduced by the switch (one
extra table lookup, plus the "unnecessary" check for the default),
but I would think it would be tolerable.

I don't recall that anyone has mentioned it, but one neat use for a
label variable (other than in generated code) is to emulate coroutines.
I've seen some of Doug McIlroy's code that did this (using int/switch;
enum hadn't been invented).  I have a program of my own that uses a
coroutine, but since there's only one pseudo-label (besides the entry
point) so I just used a CalledBefore flag.