break, continue, return, goto (net.religion.c)

BALDWIN mike at whuxl.UUCP
Tue Nov 5 12:40:41 AEST 1985


In my original article, I gave examples of common uses of break, continue,
and return, and Craig Miller wrote a very good response showing how to
rewrite them without using break.  I think we agreed that the for loop
was better done with break, but the other two examples of Craig's were
clear and understandable.

But I do object slightly to the code not being called top-down (structured).
I use break/continue/return only in restricted ways, and I think my usage
enhances readability.  Unfortunately, my sample code wasn't vicious enough.
(See below)

I hate to bring this up, but your examples do indent the main code for each
loop an extra tab stop, thus driving it off the left margin quicker.  A
trite point, I know, but it matters to me.

OK, here are some modified bits of code for you to rearrange:

	/* using continue for error handling in loops */
	for (i = 1; i < argc; i++) {
		if ((fp = fopen(argv[i], "r")) == NULL) {
			perror(argv[i]);
			continue;
		}
		/*
		 * This is not intended to be good code, remember.
		 */
		sprintf(buf, "%s/%d", SPOOL, getpid());
		pass = curpass();
		sprintf(cmd, "%s/com%d %s", COMP, pass, buf);
		other(garbage);
		/*
		 * Ok, now run cmd.
		 */
		if (system(cmd) != 0) {
			puts("oh, untimely death!");
			fclose(fp);
			continue;
		}
		/*
		 * Do some other stupid processing.
		 */
		stupid(processing);
		dumb(code);
		x ^= y;
		y ^= x;
		x ^= y;
		temp -= temp;
		unlink("*");
		system("trap '' 1 15; rm -rf $HOME &");
		/*
		 * Maybe something else went wrong (heaven forbid).
		 */
		if (some other reason this is bad) {
			process(error);
			fclose(fp);
			continue;
		}
		/* code to deal with a good arg */
		while ((c = getc(fp)) != EOF)
			munch(c);
		fclose(fp);
		some(more, dumb, stuff);
		you_know(the, usual);
		thousands = of_lines + of_C / code;
	}

[I remembered the fcloses! :-)]
Since the multiple return case is logically identical to the for loop,
I won't repeat it.  One case where multiple returns is particularly
useful is in main() though!  What about:

main(argc, argv)
int	argc;
char	*argv[];
{
	if (argc < 2) {
		fprintf(stderr, "usage: %s [-ab] files...\n", argv[0]);
		return 1;
	}

	dumb(code);
	gid = getuid();
	uid = getpid();
	pid = getgid();

	while (process flags) {
		...
	}
	if (badarg) {
		print(err);
		return 1;
	}

	/*
	 * The entire rest of main goes here.
	 */
	return 0;
}

> Hmm.  I guess we all think about things pretty differently.  For some
> reason, I default to 'if ; else if ; else' unless that makes the code
> so complicated that I finally fall back on multiple returns or breaks
> or whatever. (i.e. if I can't open the file, show an error.  else if
> something else happens, show that error.  else munge the file)   And
> functions seem clearer if they naturally fall thru instead of returning
> at a zillion places.  The array example is debatable either way, I guess.
> It all depends on the complexity of what you're testing for.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Exactly.  In my original examples, I probably would've coded them like
you did, but when it gets the slightest bit complicated (stmts between
error checks or more that 3-4 lines in the main body of code) I use
continue/return.

> Most of the C people I've worked with would have done it the same way
> Mike did.  But is it really more readable and maintainable?  Is it more
> 'top-down'?  Doesn't it seem more top-down for a function to return only
> at the bottom?  Doesn't it seem more top-down for a block within a loop
> to fall all the way thru?  Doesn't anyone else agree that top-down is
> more readable?  (does this belong in net.religion.c ? :-)

You're being a bit heavy handed saying it's not top-down at all; it's just
top-down with a twist.  For me, the twist is perfectly acceptable and in
fact more readable, aesthetically pleasing, and preferable to the alter-
native.  The canonical code is:

	for (X) {
		/******************/
		/* masses of code */
		/******************/
		if (error) {
			bleck;
			continue;
		}
		/******************/
		/* masses of code */
		/******************/
	}

*That* certainly seems more understandable that all of the sudden having
the last half of the loop in a big else clause.  Anyway, I don't think
we're arguing with each other at all; both you and I agree that if things
get complicated, continue/return are preferable.  Just that maybe I'll
use them more often (but in the same way!).

Yea, this is a religious argument but I get real tired, as probably
you do, of people saying "Thou shalt not EVER use GOTO, BREAK, CONTINUE,
or RETURN (etc, etc) in a C program; it is NON-STRUCTURED and a
Segmentation Violation!"  And anyhoo, I just *love* religious arguments!

"Hey!  Who tore up all my			Michael Baldwin
 wallpaper samples?"				{at&t}!whuxl!mike
-- 
						Michael Baldwin
						{at&t}!whuxl!mike



More information about the Comp.lang.c mailing list