Path: utzoo!utgpu!watmath!att!chinet!john From: john@chinet.chi.il.us (John Mundt) Newsgroups: comp.lang.c Subject: Re: Oh noooooo!! Message-ID: <9511@chinet.chi.il.us> Date: 8 Sep 89 01:09:26 GMT References: <7598@goofy.megatest.UUCP> <34566@apple.Apple.COM> Reply-To: john@chinet.chi.il.us (John Mundt) Organization: Chinet - Public Access Unix Lines: 103 In article <34566@apple.Apple.COM> ftanaka@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@chinet.chi.il.us (312) 998-5007 (Day voice) || -432-8860 (Answer Mach) && -432-5386 Modem