C-STYLE (goto?)

Chris Torek chris at umcp-cs.UUCP
Sat Aug 30 22:47:46 AEST 1986


>In article <3253 at brl-smoke.ARPA> jeff at isi-vaxa.ARPA writes:
>>	setup_step_1;
>>	if ( (status = step_1()) == FAILURE )
>>	    goto abort_operation;
	...
>>	setup_step_n;
>>	if ( (status = step_n()) == FAILURE )
>>	    goto abort_operation;
>>
>>abort_operation:
>>
>>	cleanup();
>>	return (status);

>>Now, I know a lot of people detest this because of the use of goto's ....

In article <264 at killer.UUCP> toma at killer.UUCP (Tom Armistead) replies:
>There is always the use of setjmp and longjmp to acomplish this task ....
[example deleted]
>This will accomplish the same thing and possibly not affend the goto haters,
>although it is somewhat harder to follow if you are no farmiliar with 
>setjmp() and lonjmp().

Alas, longjmp() is nothing more than goto in disguise.  Indeed,
this is a far more powerful version of goto than the `plain C'
goto, and should by rights be correspondingly more offensive to
goto haters.  In general, when choosing between two existing
primitives, if one is less powerful but does what you need, use
that.  When designing primitives, the choice is more difficult:
something that does less is easier to understand, but you may need
too many of those things, making the whole harder to comprehend.

As to a specific solution to the original problem above, I think
there is no `best' answer, at least not without more information.
I happen to like the pointer table method proposed by grt at twitch;
it can be expanded in a useful way for recovery and/or error
explanation:

	int	dostep1(), dostep2(), dostep3(), dostep4();
	int	fix1or3(), fix2();

	struct step {
		char	*s_name;	/* name of this step */
		int	(*s_func)();	/* function that implements it */
		int	(*s_fixup)();	/* repair after error */
	} steps[] = {
		{ "step1",	dostep1,	fix1or3 },
		{ "step2",	dostep2,	fix2 },
		{ "step3",	dostep3,	fix1or3 },
		{ "step4",	dostep4,	0 },
		0			/* marks end of table */
	};

	f()
	{
		register struct step *s;
		int status;

		for (s = steps; s->s_func != NULL; s++) {
			if ((status = (*s->s_func)()) != SUCCESS) {
				if (s->s_fixup == NULL ||
				    (*s->s_fixup)(status) != SUCCESS) {
					fprintf(stderr, "\
	Unrecoverable failure in %s, code %d\n",
						s->s_name, status;
					break;
				}
			}
		}
		return (status);
	}

There may be cases, however, where a direct-coded state machine
with a `switch' statement would be better; and there may be cases
where the original code runs fastest and/or is clearest (whichever
is more important to the coder/maintainer and user).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris at umcp-cs		ARPA:	chris at mimsy.umd.edu



More information about the Comp.lang.c mailing list