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