for(;;) or while(1)?

C

CBFalconer

John said:
[snip]
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;

I'm not sure exactly how that improves portability?

My problem with this structure is that it does not clearly convey
that c is dependent on b and a, and that b is dependent on a. I
would rather have that relationship visually reinforced by nesting
even if it means marching halfway across the page, because then I
can see the relationship and its extent at a glance, instead of
groveling through the source.

I am a proponent of goto, in its place. This is not it. I would
code that snippet as:

int error_code = MEM_ERROR; /* default */

a = b = c = NULL;
if (a = malloc(sz_a)) {
...calculations using a...
if (b = malloc(sz_b)) {
...calculations using a and b...
if (c = malloc(sz_c)) {
...calculations using a, b and c...
error_code = NO_ERROR;
}
}
}
free (c);
free (b);
free (a);

and I would be more inclined to invert the selections to put the
good case at the end, assuming I don't need to calculate things
before the mallocs:

a = b = c = NULL;
if (!(a = malloc(...))) error(AFAILS);
else if (!(b = malloc(...))) error(BFAILS);
else if (!(c = malloc(...))) error(CFAILS);
else { /* we can go to work */
/* the real stuff goes here */
error(NOERROR); /* or some such */
}
free(c); free(b); free(a);
 
N

Noah Roberts

I am a proponent of goto, in its place. This is not it. I would
code that snippet as:

int error_code = MEM_ERROR; /* default */

a = b = c = NULL;
if (a = malloc(sz_a)) {
...calculations using a...
if (b = malloc(sz_b)) {
...calculations using a and b...
if (c = malloc(sz_c)) {
...calculations using a, b and c...
error_code = NO_ERROR;
}
}
}
free (c);
free (b);
free (a);

and I would be more inclined to invert the selections to put the
good case at the end, assuming I don't need to calculate things
before the mallocs:

a = b = c = NULL;
if (!(a = malloc(...))) error(AFAILS);
else if (!(b = malloc(...))) error(BFAILS);
else if (!(c = malloc(...))) error(CFAILS);
else { /* we can go to work */
/* the real stuff goes here */
error(NOERROR); /* or some such */
}
free(c); free(b); free(a);

I believe that both of these examples blow up if one of your allocs
fail. This is the problem the goto advocates are trying to solve.

NR
 
N

Noah Roberts

Noah said:
I believe that both of these examples blow up if one of your allocs
fail. This is the problem the goto advocates are trying to solve.

Nevermind, I always thought free(NULL) blew up. I stand corrected.

Both of your examples are much better than the goto stuff you responded
to. I also like the 2nd better than my own but I wrote mine under
mistaken assumptions :p

NR
 
B

Brett Frankenberger

I believe that both of these examples blow up if one of your allocs
fail. This is the problem the goto advocates are trying to solve.

I believe that if one or more of the malloc()'s fails, he'll end up
calling free(0) one or more times. I also believe that calling free(0)
is allowed and does nothing.

-- Brett
 
C

CBFalconer

Noah said:
Nevermind, I always thought free(NULL) blew up. I stand corrected.

Both of your examples are much better than the goto stuff you responded
to. I also like the 2nd better than my own but I wrote mine under
mistaken assumptions :p

That's why I initialize the pointers to NULL. free(p), when p is
not initialized to either NULL or a value returned by malloc, will
blow up.
 
R

Ridimz

Arthur J. O'Dwyer said:
Please don't post attachments to non-binaries groups.
A simple link to Google Groups, or, even better, a quick
reminder to "look three messages up the darn thread and
*read* it" would have sufficed.

And in general, don't use spaces in filenames. Some
uudecode clients might not even parse your attachment
correctly (I dunno what any RFC on the topic says; I'm
just pointing out the possibility).

-Arthur

Thanks for the tips! No that you have enhanced my knowledge of newsgroup
postings, I'll make every effort to refrain from doing it again.

Ridimz
 
D

Dave Thompson

Noah Roberts <[email protected]> writes:
while (always)
get input
if input is quit then die

do something
...

but it is much better do do ['structured' with boolean]
"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, <snip>

Ada:
[<name>:] loop
<some stuff>;
exit [<name>] when <condition>;
<other stuff>;
end loop [<name>];
or
... for <var> in <range> loop ... similarly
... while <othercondition> loop ... similarly

LISP allows you to construct any syntax you like using macros, within
the normal parentheses and lexing rules. But I don't know if I would
count that as in the language, and mainstreamness is debatable.

Bourne-family shells allow multiple statements in the condition of a
while or until construct and only the "result" of the last is tested,
so the effect is the same although the syntax is less clear.
Although shell is debatably not a programming language at all.

FORTH does effectively the same thing, since it has no real statement
boundaries. Again not very mainstream.

- David.Thompson1 at worldnet.att.net
 
G

goose

Micah Cowan said:
That's all well and good: but what if you needed to use a before
you had the details on exactly what size you needed b to be?

ok then, how about this:
x = y = z = NULL;
if (x = malloc (a)) {
...
if (y = malloc (b)) {
...
if (z = malloc (c)) {
...
}
}
}

if (x) free (x);
if (y) free (y);
if (z) free (z);

much cleaner, plus structured as well (the indentation
indicates very clearly to me that successfull allocation
of x will allow allocation of y, which if successfull
will allow allocation of z).

if you need to *handle* the error at some point, then just
add in an integer to keep track of it

int error = 0;
x = y = z = NULL;
if (x = malloc (a)) {
...
if (y = malloc (b)) {
...
if (z = malloc (c)) {
...
} else error = 1;
} else error = 2;
} else error = 3;

if (x) free (x);
if (y) free (y);
if (z) free (z);

switch (error) {
case 1: printf ("no mem for z occurred\n"); break;
case 2: printf ("no mem for y occurred\n"); break;
case 3: printf ("no mem for x occurred\n"); break;
default: printf ("no error\n");
}
 
G

goose

Noah Roberts said:
I believe that both of these examples blow up if one of your allocs
fail. This is the problem the goto advocates are trying to solve.

where does it blow up ? what does it do wrong if the malloc fails ?

goose,
i must be dense today, or something like that :)
 
N

Noah Roberts

goose said:
where does it blow up ? what does it do wrong if the malloc fails ?

goose,
i must be dense today, or something like that :)

You are just comming in late to a thread and didn't read the whole thing.

NR
 
C

CBFalconer

goose said:
.... snip ...

if you need to *handle* the error at some point, then just
add in an integer to keep track of it

int error = 0;
x = y = z = NULL;
if (x = malloc (a)) {
...
if (y = malloc (b)) {
...
if (z = malloc (c)) {
...
} else error = 1;
} else error = 2;
} else error = 3;

if (x) free (x);
if (y) free (y);
if (z) free (z);

switch (error) {
case 1: printf ("no mem for z occurred\n"); break;
case 2: printf ("no mem for y occurred\n"); break;
case 3: printf ("no mem for x occurred\n"); break;
default: printf ("no error\n");
}

Complications not needed. The equivalent is:

....
x = y = z = NULL
if (!(x = malloc(a))) printf("...");
else if (!(y = malloc(b))) printf("...");
else if (!(z = malloc(c))) printf("...");
else {
....
}
free(z); free(y); free(x);

( If you don't like the "!(" replace with "NULL != (" )

and you can always factor "malloc(b)" etc. into a routine:

T *routine(b, others)
{
....
return malloc(b);
}

if you must have independent operations between the mallocs.
routine may even include the printf and be common to all three
cases, for net code reduction.

I think I said all this earlier. Maybe that was another thread.
 
L

Larry Doolittle

Complications not needed. The equivalent is:
....
x = y = z = NULL
if (!(x = malloc(a))) printf("...");
else if (!(y = malloc(b))) printf("...");
else if (!(z = malloc(c))) printf("...");
else {
....
}
free(z); free(y); free(x);
and you can always factor "malloc(b)" etc. into a routine:
T *routine(b, others)
{
....
return malloc(b);
}
if you must have independent operations between the mallocs.

This is also an interesting place for a "," (comma) operator.
x = y = z = NULL
if ( !(x = malloc(a))) printf("...");
else if (setup1(x), !(y = malloc(b))) printf("...");
else if (setup2(x,y),!(z = malloc(c))) printf("...");
else {
....
}
where setup1() and setup2() can be either true functions,
or just some simple in-line code.

It doesn't use malloc(), but you can see a similar interaction
of the comma operator and a chain of else-if's in busybox's
date.c:date_conv_ftime() routine. While a bit unusual,
it doesn't take long to grasp, and the code path is greatly
simplified compared to other constructs. This is the author
speaking, so you can take this as a totally unbiased assessment.

- Larry
 
G

goose

CBFalconer said:
Complications not needed. The equivalent is:

....
x = y = z = NULL
if (!(x = malloc(a))) printf("...");
else if (!(y = malloc(b))) printf("...");
else if (!(z = malloc(c))) printf("...");
else {
....
}
free(z); free(y); free(x);

but what if my "error handler" needs to do more than
print a diagnostic ? changing it to the following:

x = y = z = NULL
if (!(x = malloc(a))) {
/* close files */
/* restore signals */
/* print a message */
}
else if (!(y = malloc(b))) {
/* close files */
/* restore signals */
/* print a message */
}
else if (!(z = malloc(c))) {
/* close files */
/* restore signals */
/* print a message */
}

else {
....
}
free(z); free(y); free(x);

and now /that/ does look complicated. with switch
statement, you can at least add tons of error handling
cpode without it getting in the way of readability of
the logic.
( If you don't like the "!(" replace with "NULL != (" )

and you can always factor "malloc(b)" etc. into a routine:

T *routine(b, others)
{
....
return malloc(b);
}

this is best, really.
if you must have independent operations between the mallocs.
routine may even include the printf and be common to all three
cases, for net code reduction.

I think I said all this earlier. Maybe that was another thread.

no, i came into the thread late, i think :)

goose,
latecomer
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top