Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > acceptable use of goto?

Reply
Thread Tools

acceptable use of goto?

 
 
Jack Klein
Guest
Posts: n/a
 
      03-21-2008
On Thu, 20 Mar 2008 09:15:41 -0700 (PDT), myheartinamerica
<(E-Mail Removed)> wrote in comp.lang.c:

> Hello,
>
> I was doing some simple database programming and encapsulating
> different
> queries in functions. After each library call, I check the return
> value. After
> some return values, it makes no sense to continue, so I returned an
> error code.
> Pseudocode is something like this:
>
> int query_customer(const char* customer)
> int retval = library_call_1()
> if (retval == ERROR) { return -1}
> retval = library_call_2()
> if (retval == ERROR) { return -1}
> retval = library_call_3()
> if (retval == ERROR) { return -1}
> /* process data */
> /* cleanup handles, allocations, etc... */
> return some_inportant_value
>
> When I came in this morning, a coworker had rewritten my code. I'm
> quick second
> guess myself, so I assumed that his was more correct. It was something
> like:
>
> int query_customer(const char* customer)
> int retval = library_call_1()
> if (retval == ERROR) { some_important_value = MY_ERROR_CODE }
> retval = library_call_2()
> if (retval == ERROR) { some_important_value = MY_ERROR_CODE }
> retval = library_call_3()
> if (retval == ERROR) { some_important_value = MY_ERROR_CODE }
> /* process data */
> /* cleanup handles, allocations, etc... */
> return some_inportant_value
>
> So, he would continue to make the other library calls, even if the
> previous
> ones had failed (meaning that the later ones couldn't be successful).
>
> It got me thinking, that maybe there was a better way to do this, but
> I'm not
> sure what that is. I'm thinking about using goto's and a label, like
> this:
>
> int query_customer(const char* customer)
> int retval = library_call_1()
> if (retval == ERROR) {
> some_important_value = MY_ERROR_CODE;
> goto clean_up;
> }
> retval = library_call_2()
> if (retval == ERROR) {
> some_important_value = MY_ERROR_CODE;
> goto clean_up;
> }
> retval = library_call_3()
> if (retval == ERROR) {
> some_important_value = MY_ERROR_CODE;
> goto clean_up;
> }
> /* process data */
> clean_up:
> /* cleanup handles, allocations, etc... */
> return some_important_value
>
>
> Is there some better way to do this? Is the use of goto a good example
> of it's
> usefulness?


Actually, since you mention in another post that the function calls
are not all clean, I prefer something like this:

result_t my_func(some_params)
{
result_t result = OK;
/* example resource allocation */
FILE *f = NULL;
data_type *ptr = NULL;

for (,,)
{
f = fopen(/*...*/);
if (!f)
{
result = FILE_ERROR;
break;
}
data_type = malloc(/*...*/);
if (!data_type)
{
result = MEM_ERROR;
break;
}
if (is_invalid(param1)
{
result = BAD_DATA_ERROR;
break;
}
/* etc. */
/* finally */
break;
}
if (f) fclose(f);
free (ptr);
return result;
}

Enclosing the test in a loop allows using break to replace goto, which
is all that C's various control structures really do, anyway.

Two advantages, however, to anyone reading the code, including
yourself a year from now:

1. All break statements in the loop go to the same place, you don't
have to search back and forth through the code to see whether all goto
targets are the same or not.

2. You know a break statement always goes forward, never backward.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
Reply With Quote
 
 
 
 
Ed Prochak
Guest
Posts: n/a
 
      03-21-2008
On Mar 21, 12:06 am, Jack Klein <(E-Mail Removed)> wrote:
> On Thu, 20 Mar 2008 09:15:41 -0700 (PDT), myheartinamerica
> <(E-Mail Removed)> wrote in comp.lang.c:
>
>
>
> > Hello,

>
> > I was doing some simple database programming and encapsulating
> > different
> > queries in functions. After each library call, I check the return
> > value. After
> > some return values, it makes no sense to continue, so I returned an
> > error code.
> > Pseudocode is something like this:

[]
>
> > It got me thinking, that maybe there was a better way to do this, but
> > I'm not
> > sure what that is. I'm thinking about using goto's and a label, like
> > this:

>

[]
>
> > Is there some better way to do this? Is the use of goto a good example
> > of it's
> > usefulness?

>
> Actually, since you mention in another post that the function calls
> are not all clean, I prefer something like this:
>
> result_t my_func(some_params)
> {
> result_t result = OK;
> /* example resource allocation */
> FILE *f = NULL;
> data_type *ptr = NULL;
>
> for (,,)
> {
> f = fopen(/*...*/);
> if (!f)
> {
> result = FILE_ERROR;
> break;
> }
> data_type = malloc(/*...*/);
> if (!data_type)
> {
> result = MEM_ERROR;
> break;
> }
> if (is_invalid(param1)
> {
> result = BAD_DATA_ERROR;
> break;
> }
> /* etc. */
> /* finally */
> break;
> }
> if (f) fclose(f);
> free (ptr);
> return result;
>
> }
>
> Enclosing the test in a loop allows using break to replace goto, which
> is all that C's various control structures really do, anyway.
>
> Two advantages, however, to anyone reading the code, including
> yourself a year from now:
>
> 1. All break statements in the loop go to the same place, you don't
> have to search back and forth through the code to see whether all goto
> targets are the same or not.
>
> 2. You know a break statement always goes forward, never backward.
>
> --
> Jack Klein



While it is a stylistic difference, if I used the loop style I would
make sure the loop executed exactly one time, just to be safe. Bu I
still prefer the goto.
Ed
 
Reply With Quote
 
 
 
 
Ed Prochak
Guest
Posts: n/a
 
      03-21-2008
On Mar 20, 4:18 pm, Flash Gordon <(E-Mail Removed)> wrote:
> Ed Prochak wrote, On 20/03/08 17:17:
>
> > On Mar 20, 12:55 pm, myheartinamerica <(E-Mail Removed)>
> > wrote:
> >>> *) This, of course, depends on the function calls being clean like that.
> >>> When faced with more complicated calls, you can use nested 'if's.
> >> In this situation, the calls are indeed more complex. Nested if
> >> statements, while producing the correct output, would be obnoxiously
> >> nested at 4+ levels deep. I've thought about that solution many times,
> >> but stylistically felt like it was the wrong solution, even more so
> >> than using the goto statement.

>
> > There is nothing wrong with using the goto statement, especially for
> > error recovery like this. Even if you are a dyed in the wool
> > structured programmer, the rule is: Branching (goto) should only go
> > Forward in the code, never backwards, except for well defined loops.

>
> Wait until you have worked on code that branches forward in to a loop,
> forward within the loop at various points, then forward out of the loop.
> Then tell me that your rule is sufficient. BTW, I'm referring to real
> code I've had to maintain, and it is horrible.
>
> > The misuse of goto is exactly this: haphazardly branching back to
> > earlier portions of code. You case does not fall into that category.
> > So use it if you prefer as you suggest: to branch over code which will
> > fail due to the earlier failure. Naming the label properly can make
> > things very easy to read. And the style is a good one.

>
> I agree that it can be used usefully, but there are more options for
> abusing it that you have listed.
> --
> Flash Gordon


True, I wasn't trying to be exhaustive in listing abuses. And I have
seen and maintained code that abused the avoidance of goto (the worst
case was a program with a seven page while loop.)

I guess I simplified the rules a little too much. Thanks for the
follow up.
Ed
 
Reply With Quote
 
Andrey Tarasevich
Guest
Posts: n/a
 
      03-21-2008
Jack Klein wrote:
> ...
> Actually, since you mention in another post that the function calls
> are not all clean, I prefer something like this:
>
> result_t my_func(some_params)
> {
> result_t result = OK;
> /* example resource allocation */
> FILE *f = NULL;
> data_type *ptr = NULL;
>
> for (,,)
> {
> f = fopen(/*...*/);
> if (!f)
> {
> result = FILE_ERROR;
> break;
> }
> data_type = malloc(/*...*/);
> if (!data_type)
> {
> result = MEM_ERROR;
> break;
> }
> if (is_invalid(param1)
> {
> result = BAD_DATA_ERROR;
> break;
> }
> /* etc. */
> /* finally */
> break;
> }
> if (f) fclose(f);
> free (ptr);
> return result;
> }
>
> Enclosing the test in a loop allows using break to replace goto, which
> is all that C's various control structures really do, anyway.
>
> Two advantages, however, to anyone reading the code, including
> yourself a year from now:
>
> 1. All break statements in the loop go to the same place, you don't
> have to search back and forth through the code to see whether all goto
> targets are the same or not.
>
> 2. You know a break statement always goes forward, never backward.
> ...


I'd find such a construct more or less appropriate in a situation when
an error condition triggers a retry attempt. But as a replacement for a
'goto', i.e. when a cycle is not really a cycle, it is completely
unacceptable in my opinion. The damage to the readability of the code
done by the use of misleading cycle construct far outweighs anything a
'goto' would do.

--
Best regards,
Andrey Tarasevich
 
Reply With Quote
 
James Harris
Guest
Posts: n/a
 
      03-21-2008
On 20 Mar, 16:15, myheartinamerica <(E-Mail Removed)> wrote:

....

> It got me thinking, that maybe there was a better way to do this, but
> I'm not
> sure what that is. I'm thinking about using goto's and a label, like
> this:
>
> int query_customer(const char* customer)
> int retval = library_call_1()
> if (retval == ERROR) {
> some_important_value = MY_ERROR_CODE;
> goto clean_up;
> }
> retval = library_call_2()
> if (retval == ERROR) {
> some_important_value = MY_ERROR_CODE;
> goto clean_up;
> }
> retval = library_call_3()
> if (retval == ERROR) {
> some_important_value = MY_ERROR_CODE;
> goto clean_up;
> }
> /* process data */
> clean_up:
> /* cleanup handles, allocations, etc... */
> return some_important_value
>
> Is there some better way to do this? Is the use of goto a good example
> of it's
> usefulness?


So you are looking for a way to run a number of initial checks and
bring them and the main code all back together at the end to either
clean up or to achieve single exit? I wonder what you think of this
(and, indeed, if it would work; if there is a fault in my C perhaps
someone will correct the code). Its intention is to use a do ... while
zero construct which executes once providing a common exit point
without use of goto and a label.

int query_customer(const char* customer) {
do { /* execute once */
int retval = library_call_1()
if (retval == ERROR) {
some_important_value = MY_ERROR_CODE;
break;
}
retval = library_call_2()
if (retval == ERROR) {
some_important_value = MY_ERROR_CODE;
break;
}
retval = library_call_3()
if (retval == ERROR) {
some_important_value = MY_ERROR_CODE;
break;
}
/* process data */
} while 0;
/* cleanup handles, allocations, etc... */
return some_important_value;
}


 
Reply With Quote
 
James Harris
Guest
Posts: n/a
 
      03-21-2008
On 21 Mar, 12:17, Ed Prochak <(E-Mail Removed)> wrote:

....

> While it is a stylistic difference, if I used the loop style I would
> make sure the loop executed exactly one time, just to be safe. Bu I
> still prefer the goto.


Instead of goto and a label how do you feel about

do {
/* tests including breaks */
/* processing */
} while 0;

 
Reply With Quote
 
user923005
Guest
Posts: n/a
 
      03-21-2008
On Mar 21, 2:13*pm, James Harris <(E-Mail Removed)>
wrote:
> On 21 Mar, 12:17, Ed Prochak <(E-Mail Removed)> wrote:
>
> ...
>
> > While it is a stylistic difference, if I used the loop style I would
> > make sure the loop executed exactly one time, just to be safe. Bu I
> > still prefer the goto.

>
> Instead of goto and a label how do you feel about
>
> * do {
> * * /* tests including breaks */
> * * /* processing */
> * } while 0;


Usually works well. The goto is still helpful in the nested case:

do {
/* tests including breaks */
/* processing */
do {
/* tests including breaks */
/* processing */
do {
/* tests including breaks */
/* processing */
do {/* what if I want to break *clear* out? */
if (obscure_condition_occurs()) break;
} while 0;
} while 0;
} while 0;
} while 0;
 
Reply With Quote
 
christian.bau
Guest
Posts: n/a
 
      03-22-2008
On Mar 20, 8:18*pm, Flash Gordon <(E-Mail Removed)> wrote:

> Wait until you have worked on code that branches forward in to a loop,
> forward within the loop at various points, then forward out of the loop.
> Then tell me that your rule is sufficient. BTW, I'm referring to real
> code I've had to maintain, and it is horrible.


Some time thirty years ago it was proved that any program that uses
goto's can be rewritten without gotos. The proof is quite simple:
First, you replace all structured statements with simple statements
and gotos, so you end up with only statements of the form "expression-
statement", "goto", "if (expression) goto", with a return statement at
the end. Then you give every statement a label. Create a variable
named "label" and initialise it to the label of the first statement.
Then the rest is translated to

"while (label != <label of the return statement) {
if (label == <label of statement 1>} { statement1; label =
<label of statement2>; } // example of expression statement
else if (label == <label of statement2>} { label = <label of
goto destination>; } // example of goto statement
else if (label == <label of statement3>) { label = (expr) ?
<label of goto destination> : <label of statement4>; } // Example of
conditional goto
;;;
}

No goto statements. No structure either.
 
Reply With Quote
 
Harald van Dijk
Guest
Posts: n/a
 
      03-22-2008
On Sat, 22 Mar 2008 08:49:59 -0700, christian.bau wrote:
> On Mar 20, 8:18*pm, Flash Gordon <(E-Mail Removed)> wrote:
>> Wait until you have worked on code that branches forward in to a loop,
>> forward within the loop at various points, then forward out of the
>> loop. Then tell me that your rule is sufficient. BTW, I'm referring to
>> real code I've had to maintain, and it is horrible.

>
> Some time thirty years ago it was proved that any program that uses
> goto's can be rewritten without gotos. The proof is quite simple: First,
> you replace all structured statements with simple statements and gotos,
> so you end up with only statements of the form "expression- statement",
> "goto", "if (expression) goto", with a return statement at the end. Then
> you give every statement a label. Create a variable named "label" and
> initialise it to the label of the first statement. Then the rest is
> translated to
>
> "while (label != <label of the return statement) {
> if (label == <label of statement 1>} { statement1; label =
> <label of statement2>; } // example of expression statement
> else if (label == <label of statement2>} { label = <label of
> goto destination>; } // example of goto statement
> else if (label == <label of statement3>) { label = (expr) ?
> <label of goto destination> : <label of statement4>; } // Example of
> conditional goto
> ;;;
> }
>
> No goto statements. No structure either.


enum { STMT_1, STMT_2, STMT_3, STMT_4, RETURN } label = 0;
while (label != RETURN)
switch (label) {
case STMT_1: /* statement1; */
statement1;
label = STMT_2;
continue;
case STMT_2: /* goto STMT_3; */
label = STMT_3;
continue;
case STMT_3: /* if (expr) goto STMT_1; */
if (expr) label = STMT_1;
else label = STMT_4;
continue;
case STMT_4: /* ... */
/* ... */
}

Believe it or not, but this is extremely close to being actually useful.
Make label a static variable, change continue to return, and you are
essentially looking at
http://www.chiark.greenend.org.uk/~s...oroutines.html
 
Reply With Quote
 
Bartc
Guest
Posts: n/a
 
      03-22-2008
christian.bau wrote:
> On Mar 20, 8:18 pm, Flash Gordon <(E-Mail Removed)> wrote:
>
>> Wait until you have worked on code that branches forward in to a
>> loop, forward within the loop at various points, then forward out of
>> the loop. Then tell me that your rule is sufficient. BTW, I'm
>> referring to real code I've had to maintain, and it is horrible.

>
> Some time thirty years ago it was proved that any program that uses
> goto's can be rewritten without gotos. The proof is quite simple:
> First, you replace all structured statements with simple statements
> and gotos, so you end up with only statements of the form "expression-
> statement", "goto", "if (expression) goto", with a return statement at
> the end. Then you give every statement a label. Create a variable
> named "label" and initialise it to the label of the first statement.
> Then the rest is translated to
>
> "while (label != <label of the return statement) {
> if (label == <label of statement 1>} { statement1; label =
> <label of statement2>; } // example of expression statement
> else if (label == <label of statement2>} { label = <label of
> goto destination>; } // example of goto statement
> else if (label == <label of statement3>) { label = (expr) ?
> <label of goto destination> : <label of statement4>; } // Example of
> conditional goto
> ;;;
> }
>
> No goto statements. No structure either.


If I understood this correctly: I take my beautifully structured program,
and decompose it into simple statements and gotos.

Then I build a framework (of if or switch statements) to eliminate the
gotos?

A lot of work to eliminate the occasional goto as in the following
(uncompiled) code:

for (i=1; i<=N; +=i)
{
if (x==2) break;

switch (x)
{
case 2:
goto mylabel;
};

};
mylabel:

I want to break out of the loop when x=2, which I can do with an 'if'
statement but not with a 'switch' statement, because the latter uses the
same 'break' keyword as used for loops. I can do this with extra code but
this would generate more clutter than a goto would.

And in fact there are many other well-structured uses of goto to eliminate a
few other deficiences in the C syntax, like breaking out of a nested loop;
this is a similar problem to the above, I can't break out of a loop using
break, from inside an nested loop.

I think 'goto' used according to certain rules and situations can be
perfectly acceptable.

The above goto elimination scheme sounds useful however when port a language
with gotos, or with different control structures, to one without.

--
Bart



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Acceptable Load on WAN Link ciscoham Cisco 3 10-20-2005 04:28 PM
MCAD/MCSD certificate testing: whats an acceptable exam score rate .Net Sports ASP .Net 2 05-03-2005 05:31 PM
acceptable way to program steve Java 34 02-20-2005 06:37 PM
Is this trick with reset acceptable? valentin tihomirov VHDL 6 04-14-2004 05:52 PM
An "acceptable" use of break Chris Potter C Programming 26 11-07-2003 09:21 PM



Advertisments