gotos

Herman Rubin cik at l.cc.purdue.edu
Sat Apr 16 23:02:37 AEST 1988


In article <3470 at bunker.UUCP>, garys at bunker.UUCP (Gary M. Samuelson) writes:
> In article <748 at l.cc.purdue.edu> cik at l.cc.purdue.edu (Herman Rubin) writes:
> >
> >Here is a challenge to the denigrators of goto.
> 
> I am not sure I qualify, absolutely, but how about:
> 
> Case 5:	b >>= g16;
> 	m |= b;
> 	x = *(--geom);
> 	if (TEST)
> 	{	
> 		if(ODD(x))
> 			Case2();
> 		else
> 			Case1();
> 	}
> 	else
> 	{
> 		g4 = (x+1)/2;
> 		if(ODD(x))
> 			Case3();
> 		else
> 			Case4();
> 	}
> 
> Readability improved through indentation at no extra charge.
> Extraneous semi-colons tossed also.  And, yes, I normally do
> such things when I have to deal with ugly code.
> 
> Now give me something hard.
> 
> Gary Samuelson

--For those who have not seen the original posting, replace
	Casej() 	by	goto Casej.		---------

I have no qualms with using or not using indentations.  Also I think that
the initial use of semi-colons by C was a mistake, and rather than getting
obscure error messages, I admit I use too many.  Now to the main point.

I stated that this was a _fragment_ of code.  After leaving Case5, this
part of the code is not reached again until entered in the generation of
a new item.  That is, after going to one of the other cases, this block of
code is _not_ to be returned to.  Also, the cost of a subroutine call is
huge compared with the cost of a goto.

One of those responding by mail correctly deduced the original procedure,
which can easily be written without gotos.  The actual procedure as I would
code it uses gotos even more, as it can be recognized that certain information
may be in a reusable form.  For example, instead of 

	*(geom++) = z;

in one case, followed by reading the item in the transferred case, just goto
the intermediate step.

The idea of the whole section of code, in a non-goto format, with most of the
details omitted, as follows:  (Please ignore C grammatical errors.)
	
	{if(w==3)
		{i=3; g4=1; break}
	else if (EVEN(w)){....}
	else if(w==5)ABORT;
	else .....}

	while(i>1)
	{switch(i)
		case 2: b >>= *(--geom); m |= b; i=1; break;
		case 3: (details omitted)
		case 4: (details omitted)
		case 5: as in the posted code, except goto Casej is replaced
			by i = j; break;
		case 6: (details omitted)
		case 7: (details omitted)
		default: (details omitted)}
	
	termination code (details omitted)

A simple analysis of the instructions generated shows that much of the time is
spent in storing the value of i (even if you can get your compiler to put it
into a register) and carrying out the switch comparisons.  In addition, there
are many ways to combine operations using the structure of the code, and 
knowledge of the algorithm, to eliminate unnecesary transfers.  The goto-less
code has at least twice as many machine goto instructions as the goto code for
the transfers to casej, and each there is an additional comparison instruction
for each case move.  I deliberately eliminated the storage of i for i<8.

When your optimizing compiler can convert case switches with case numbers 
generated into the more efficient code such as I would write, I will consider
eliminating those gotos.  Alternatively, those features may be added to the
language.  However, I cannot see how even the most brilliant optimizing 
compiler could see some of the other uses of goto in the algorithm.

There seems to be far more that the algorithm producer can think of than the
language designer realizes is pos



More information about the Comp.lang.c mailing list