Noah Roberts said:
Yeah, that was the point I was making. Some people like to
create a macro like that, I usually just use the actual loop when
I am testing code. I don't like to use forever loops in real
code but if I where to do so I might define something like that.
Yes, it is much better to use a condition to exit. Many times
people do something like the following:
while (always)
get input
if input is quit then die
do something
...
but it is much better do do something like this:
boolean quit = false /* or continue = true */
while (!quit)
get input
if input is quit then quit = true
else do something
...
"Much better"... IYO. I frequently prefer the former, and call it
a "mid-test" loop. IMO, mainstream programming languages have
syntax for a pretest loop and posttest loop, but no one supports
the midtest loop. So I use the former example above, which is the
closest thing available, rather than try to force it to be a
pretest loop.
Another way of forcing it to look like a pretest loop (but it
still isn't) is something like:
while ((c = getchar()) != EOF)
...
The second version is "structured" code whereas the first is not
(two exits).
Wrong. There is exactly one exit. It seems very structured to me,
if used properly: even if the syntax may not be as clean, it's
less ugly (to me) than going through loops to make it "proper".
Sometimes it is better to break structure, but it
always sacrifices maintainability and readability;
Not true. I frequently break structure for the explicit purpose
to improve portability. The typical case being something like:
int error_code = NO_ERROR;
a = malloc(sz_a);
if (a == NULL) { error_code = MEM_ERROR; goto my_end; }
(...calculations using a...)
b = malloc(sz_b);
if (b == NUL) { error_code = MEM_ERROR; goto cleanup_a; }
(...calculations using a and b...)
c = malloc(sz_c);
if (c == NUL) { error_code = MEM_ERROR; goto cleanup_b };
(...calculations using a, b and c...)
free (c);
cleanup_b:
free (b);
cleanup_a:
free (a);
my_end:
return error_code;
The alternatives include nesting a ton of if statements (which in
many cases can get cumbersome quickly), code repetition (always
something I strive to avoid; it usually leads to
bugs/inconsistencies), and checking some combination of a, b or c
before each and every operation involving them (ouch!!!). There's
also farming each block out to a separate function, which is
often what I try first, but sometimes this can be even more
cumbersome, especially if there are a lot of other variables
involved that would need to be passed around.
99.9999999% of the time it is not necissary to write unstructured
code and since it is a mistake to do so you shouldn't except for
that .000000001% of the time when you need to.
This percentage is somewhat exaggerated (to me). I've found it closer to
between 97-99% of the time, personally.
-Micah