Oh noooooo!!

John Mundt john at chinet.chi.il.us
Fri Sep 8 11:09:26 AEST 1989


In article <34566 at apple.Apple.COM> ftanaka at Apple.COM (Forrest Tanaka) writes:
>I've been using gotos regularly in my C code for quite a few months--in one
>specific situation.

Pathetic justifications deleted and sample of code follows.

>#define null 0
>char *
>SomeFunction ()
>    {
>    char *Block0;
>    char *Block1;
>    char *Block2;
>
>    Block0 = (char *) null;
>    Block1 = (char *) null;
>    Block2 = (char *) null;
>    if ((Block0 = AllocateMemory ()) == (char *) null)
>        goto Abort;
>    if ((Block1 = AllocateMemory ()) == (char *) null)
>        goto Abort;
>    if ((Block2 = AllocateMemory ()) == (char *) null)
>        goto Abort;
>    return Block0;
>
>Abort:
>    if (Block0 != (char *) null)
>        DeallocateMemory (Block0);
>    if (Block1 != (char *) null)
>        DeallocateMemory (Block1);
>    if (block2 != (char *) null)
>        DeallocateMemory (Block2);
>    return (char *) null;
>    }
>
>When I was trying to come up with a consistent and convenient way to handle
>error conditions within functions, I examined what I would do if I was writing
>the function in assembly language.  I would probably check for an error when
>a function like AllocateMemory returns, and if there was an error, branch to
>some error handling code.  Ah hah! thought I.  This is is possible in C with
>the goto statement.  Now I never have to have a bunch of nested ifs and I can
>deal with undoing what I had done in that function before the error occured.

But you don't have to use gotos at all in that situation.  You could write
the thing this way, and save the heretical goto:


#define null (char *) 0

char * SomeFunction () {
    char *Block0, *Block1, *Block2;

    Block0 = Block1 = Block2 = null;

    if ((Block0 = AllocateMemory ()) != null
    	&& (Block1 = AllocateMemory ()) !=  null
	&& (Block2 = AllocateMemory ()) !=  null)
    return Block0;

    if (Block0 != null)
        DeallocateMemory (Block0);
    if (Block1 != null)
        DeallocateMemory (Block1);
    if (block2 != null)
        DeallocateMemory (Block2);
    return null;
}


The above code does exactly the same thing, and avoids the dreaded
goto!  I think it is just as clear as the goto coding.  

However, my hands are not clean, and there are a few gotos in my
code when I am deep into some nested somthing, as in

	while (something) {
		...
		do {
			something_grandiose()
			for ( ; this < that; ) {
				...
				while (something_else) {
					...
					if (error)
						goto sloth;
				}
			}
		} while marvelous_things();
	}
	return;

	sloth:  /* Sorry! */
		bail_out();

Granted, no one ought to nest like that, but when you do :-), the
goto is a quick way to get out without a ton of flag checking.  But
I always label the goto "sloth" so that everyone knows what kind of
person I am to put goto's  into my program in the first place.  
-- 
---------------------
John Mundt   Teachers' Aide, Inc.  P.O. Box 1666  Highland Park, IL
john at chinet.chi.il.us
(312) 998-5007 (Day voice) || -432-8860 (Answer Mach) && -432-5386 Modem  



More information about the Comp.lang.c mailing list