regarding "goto" in C

K

Keith Thompson

Herbert Rosenau said:
Crappy design:


The same without goto:

if ((foo = init_foo_type())
&& (bar = init_bar_type())
&& (baz = init_baz_type())
) {
/* work */
}
cleanup_baz_type(baz);
cle......

That assumes each initialization can be done in a single expression
statement. That happens to be true in my example, but it needn't be,
and your transformation won't work for more complex cases. Sure, you
could write your own init_*() functions to guarantee that each piece
of initialization can be done with a single function call, but that
just moves the complexity somewhere else (which could be a good
thing).

Also, you're calling the cleanup_*() functions without checking
whether their arguments are non-NULL.
or avoiding the big if and breaking the whole work down into different
levels, hiding too much details but giving better overview of the real
work:

static int init_types(int **foo, int **bar, int **baz) {
return (*foo = init_foo_type())
&& (*bar = init_bar_type())
&& (*baz = init_baz_type());
}

static void cleanup_types(.... like init_types but cleanup.......
:
:
:
void foo(void) {
foo_type *foo = NULL;
bar_type *bar = NULL;
baz_type *baz = NULL;

if (init_types(&foo, &bar, &baz)) {
do_work(....);
}
cleanup_types(&foo, &bar, &baz);
}

I would prefere the second choice when runtime is not really critical
because it makes anything more maintenanceable and more readable.

Now you're creating new functions that are called only once. That's
not *necessarily* a bad idea, but it sometimes can lead to what you
might call structured spaghetti.

[snip]

I rarely, if ever, use gotos myself, and if I were writing the above
code I'd probably try to find a way to avoid them. Indiscriminate use
of gotos is undoubtedly dangerous. Careful use of gotos *can* be ok,
particularly if they're used only to work around a missing language
feature such as exception handling or multi-level break. And of
course it's not the least bit difficult to write horrendously bad code
without using a single goto.

Digression:

We're able to avoid gotos for the most part because the language gives
us higher level control structures. This is less true for data
structures than for control structures. A goto in a control structure
is analagous to a pointer as a data structure. In both cases, the
programmer is responsible for keeping everything consistent, and
failure to do so can be disastrous. Using explicit gotos to implement
a higher-level control structure is frowned upon; using explicit
pointers to implement a higher-level data structure (such as a linked
list or binary tree) is standard practice.
 
S

Skarmander

Herbert said:
You're right that my example is not the best. But in the short time I
found nothing that I were able to use to make from a nonsense a real
good design. For a blind hack of code that makes as such no sense it
was the best to show up other code without sense but avoiding goto.

Real design starts at much higher level and will avoid some constructs
before there is a chance to write a single statement.
I don't doubt it's possible to call some approach to design "real design"
and coincidentally have this approach avoid all cases where goto could come
in handy.

Not that it's easy, mind you. If high-level "real design" impacts how code
is written at the lowest level, there is something suspicious about it.
!! is a possibility to save typing (and mistyping, e.g. like = instead
of ==). True, yes I do never take consideration of beginners in
learning C because one has to learn the language by using it.
I'm not a beginner and I do know perfectly what !! means. Knowing what it
means and wanting to use it are two different things (as you know, of
course, through avoiding goto. :)

The = vs. == thing is indeed another wart of C best avoided, but this at
least is something even the beginners quickly grow wise to. There's not
enough code out there using the !! trick to make it as readable. You can
parse it, but it takes time. How much time code takes to *type* is all but
insignificant (I'm sure managers will tell you otherwise, but most of those
managers couldn't program if their lives depended on it, let alone judge
coding techniques.)
Yes, I don't like empty lines whenever there is a chance to avoid one,
except an empty line can stand for self declaring documentation saying
there starts a new logical block of execution. Yes, I avoid {}
whenever possible because that gives up to 2 more lines on the same
screen page.

Well, this is another one of those holy war things we'd best not touch and
chalk up to personal preference. Those things probably make a difference one
way or another, but not enough to quibble about.
But for that my editor knows how to indent right and it will prove the
matching of braces every time I ask it for. True, this all is at least
a question of style but avoiding goto and longjump is never. You would
know that when you have written one singe project that has not only to
be failsave but has to save human live in any condition and not only
some money.
Ooh, here you go making assumptions, and we all know how dangerous that is.
You're in luck, though: I'm not going to tell you I wrote the control
program for a nuclear reactor or an X-ray scanner and used goto and
longjmp() to good effect. I wouldn't turn this into a "my application field
is more sensitive to failure than yours" debate, though; this tends to be
unproductive. Some applications that saved "some money" arguably had plenty
of impact on the quality and possibly quantity of human life, too.

Even without the benefit of this no doubt insightful experience, your
assertion is mere bluster, since you're not going to prove that the use of
goto was what condemned such a project in the past. It is an appeal to
emotion that boils down to "goto makes your project bad, and in your really
important project it's a liability".

What next? "goto kills"? I'm sure it has. So have floating-point
calculations and exceptions (in other languages). In all of these cases it
is dubious to propose the features themselves were wrong. Misapplied, yes.
Easy to misapply, certainly. Never appropriate, not necessarily.

What is true is that goto (and longjmp() even more so) are hard to use
*appropriately*. This is why goto should be avoided: if you don't know why
you're using goto and not some other control structure, you're not using it
right and should stop. Write something you can control. Better, write
something that is obvious not just to you, but to anyone of slightly less
capacity than yourself. (It is useless to write code for programmers vastly
worse than yourself, since they cannot modify what they do not understand
anyway; it is likewise useless to try and be smarter than you actually are
on a bad day, which is a much more common failing.)

Programmers do not how to use goto properly either because they've *never*
been told not to use it, or because they've *always* been told not to use
it. Yes, you can shoot yourself in the foot with goto, no question about it.
Then again, you can shoot yourself in the foot with a lot of things in C.
None of this can serve as a blanket condemnation. The pitfalls of goto are
well known, and all the arguments for and against are, too. Those who are
not familiar with them should stick with "never use goto", since it makes
the world a better place for all of us. I would be the last one to advocate
changing this happy status quo.

goto has its uses. Anyone who denies this is calling Donald Knuth wrong.
Unrestricted use of goto is harmful. Anyone who denies this is calling
Edsger Dijkstra wrong. I wouldn't take either of those men on lightly
without some very good arguments, because they usually have them handy.

I'd like to close this debate with an important remark: I can count the
number of times I've used goto in applications on the fingers of one hand,
quite unlike the number of programs I've written, for which no appendages
suffice (they would if I counted in binary, though). The count for longjmp()
stands at zero.

Why? Because goto was not the appropriate solution to the problem in almost
every case. In those cases where I used it, it was. Equivalent code not
using goto of course existed, but it was less elegant and less readable.
There aren't many legitimate uses of goto -- but where they are, it is
fanaticalism to say that they, too, should be abolished because they raise
the spectre of wrongful application. It's likewise silly to say "but you can
do that without goto". Of course. Then I can say "but you can do that
without while". It doesn't really advance things.

S.
 
A

August Karlstrom

Herbert Rosenau wrote:
[snip]
True, this all is at least
a question of style but avoiding goto and longjump is never. You would
know that when you have written one singe project that has not only to
be failsave but has to save human live in any condition and not only
some money.

I doubt that C is the right tool for safety critical programs. I think
the general problem with C is not the language itself, but that it's
used outside the system programming area.

Here is a classical quote about goto:

"As for GOTO, I have this to say:

The apprentice uses it without thinking.
The journeyman avoids it without thinking.
The master uses it thoughtfully."


August
 
C

Chuck F.

Herbert said:
Break down the whole complicate thing in levels:
level description
1 show up WHAT is to do
when needed recurse level 1
2 how is it done
when needed recurse level 1 until
there is only one single step to do
or the number of steps is very short
and unconditional.

This can always be done by creating functions hiding details of
what is to do respective how is the detail done. This can (but
must not) reduce a number of if, for, while statements but will
avoid any goto by design.

Break down the whole program in a sequence of single steps. Code
each single step as own function whereas each function itself
will break down the whole function in a sequence wheras.....
...... until a single function fits on a screen size and has not
more direct nested control statemens as 3 or 4.

You would easy learn by that that C has some levels of
visibility of variables and functions and you'll learn to use
that well.

After you has learned programming in C you would have to learn
programming using C. Then you would be ready to use C instead of
basic, FORTRAN or cobol or pure assembly and forget about goto
and its existence because you'll never see a need for.

I don't think this self-aggrandizement deserves a reply. I am
quoting the whole thing to expose the foolishness.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
R

Richard Heathfield

August Karlstrom said:
Here is a classical quote about goto:

"As for GOTO, I have this to say:

The apprentice uses it without thinking.
The journeyman avoids it without thinking.
The master uses it thoughtfully."

Unfortunately, there are way too many apprentices who think they are
masters.
 
T

tmp123

August said:
I doubt that C is the right tool for safety critical programs. I think
the general problem with C is not the language itself, but that it's
used outside the system programming area.


Sorry, could you expand a few more this part?.

Thanks.
 
H

Herbert Rosenau

That assumes each initialization can be done in a single expression
statement. That happens to be true in my example, but it needn't be,
and your transformation won't work for more complex cases.

Sure, the transformation was done on your exampel, not on a more
complex one. A more complex one had gotten another transformation
because it had needed another design.

Sure, you
could write your own init_*() functions to guarantee that each piece
of initialization can be done with a single function call, but that
just moves the complexity somewhere else (which could be a good
thing).

That is why I say "make a right design and some problems going away
alone.
Also, you're calling the cleanup_*() functions without checking
whether their arguments are non-NULL.

Hey, it is the job of a cleanup that can receive errornous data to
check it. When the design says it has to handle null pointers it must
do so. If it were impossible to receive ones it would not.
Now you're creating new functions that are called only once. That's
not *necessarily* a bad idea, but it sometimes can lead to what you
might call structured spaghetti.

No, it can not because C knows of different storage classes and one
should know how to use them even on functions. The design of a
translation unit is design that can even be done before the first
statement gets written.

One time functions an excellent method to refine a job from an
overview to the last detail. Each one time function will clearly be on
storage class static to document that it is never used outside this
translation unit. So until you have a need to look into the
implementation details you can surely ignore it.

My style guide is to organise each translation unit in logical blocks
- #define and #ifdef as needed to modify #included files
- #include external definitions and declarations as needed
commonly known as header files
- defining data used by other translation units but
associated to this translation unit
- defining data and macros needed on file scope but
only in this translation unit
- declaring one time functions
- declaring other static functions
- defining local functions
- defining external callable functions
(declarations are in #included header files,
giving the compiler a chance to check prototypes
agaist the definitions)
- for each function: the same as for the whole translation unit.

[snip]

I rarely, if ever, use gotos myself, and if I were writing the above
code I'd probably try to find a way to avoid them. Indiscriminate use
of gotos is undoubtedly dangerous. Careful use of gotos *can* be ok,
particularly if they're used only to work around a missing language
feature such as exception handling or multi-level break. And of
course it's not the least bit difficult to write horrendously bad code
without using a single goto.

As sayed I have in 25 years programming C never found a cause to write
goto. I had never missed exceptions as in C++ (maybe because my
history is another 10 years of programming in assembly on highly
different mashines before I got to learn to be a C programmer).

Yes I had missed sometimes labled break, but not really as on all
places it were useful as such the complexitiy of the whole blox was
high enough to redesign as ((a copule of) one time) functions to get
off the complexity of the problem.
Digression:

We're able to avoid gotos for the most part because the language gives
us higher level control structures. This is less true for data
structures than for control structures. A goto in a control structure
is analagous to a pointer as a data structure.

No. An own function for a block of code is the same as a struct for
data. Encapsulate code to hide complexity makes more sense as it
increases the readability which increases the maintenceabiltity.

In both cases, the
programmer is responsible for keeping everything consistent, and
failure to do so can be disastrous. Using explicit gotos to implement
a higher-level control structure is frowned upon;

No, not really. That decreases only the readability and avoids
manintenanceability. It is hard to find a goto and the cause for when
you have to maintenance code you've not written or you've not touched
the sources for years.

using explicit
pointers to implement a higher-level data structure (such as a linked
list or binary tree) is standard practice.

Yes, but even there I've seen the wrong type of linked list for the
job it had to hold for. It is easy to make the wrong desin in both
data and code. Wheras it is sometimes not so easy to rework the design
before coding starts and often nearly impossible thereafter based on
time and cost needed for.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
K

Keith Thompson

Herbert Rosenau said:
No. An own function for a block of code is the same as a struct for
data. Encapsulate code to hide complexity makes more sense as it
increases the readability which increases the maintenceabiltity.

Except that the internals of a struct are visible to its callers; the
equivalent would be allowing the caller of a function to have access
to every individual statement within the function. The equivalent of
a function would be a structure whose members are hidden.
No, not really. That decreases only the readability and avoids
manintenanceability. It is hard to find a goto and the cause for when
you have to maintenance code you've not written or you've not touched
the sources for years.

Where does the "No, not really" comes from? I don't see how you're
disagreeing with what I wrote here.

(BTW, the words are "maintainability" and "maintain", not
"manintenanceability" and "maintenance".)
using explicit

Yes, but even there I've seen the wrong type of linked list for the
job it had to hold for. It is easy to make the wrong desin in both
data and code. Wheras it is sometimes not so easy to rework the design
before coding starts and often nearly impossible thereafter based on
time and cost needed for.

Agreed. (And of course the analogy between control structures and
data structures isn't absolute, but there are some interesting things
to learn from looking at things that way.)
 
C

Chris Hills

Yes, you have reason, I forget to remark it (a good reason to start in
C++).

However, I'm sure you known it is posible a workaround with a few
macros like:

#define TRY if(...(setjmp(...
#define CATCH else
#define RAISE logjmp(...

Kind regards.

Most standards that ban got also ban setjmp and logjmp
 
W

websnarf

John said:
IME, there are cases where a goto is useful, but they are few and far
between. I have no problems with gotos provided some basic rules are
followed:

1. Branch forward only.

This is nonsense.
2. Never branch into the middle of another control structure (if, for,
while, etc.)

There are cases where this leads to a performance improvement to do so.
3. Don't use goto if another control structure can do the same job.

You can always use another control structure -- the question is whether
or not doing so makes the code more complicated or slower.

I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)

The typical cases where goto is useful: 1) when escaping from more than
one level of loop control, 2) when you have more than one "clean up and
return" code fragment that can be reached from even more scenarios
(typically "clean up and return error" versus "clean up and return
sucess".) 3) Any state machine (switch often doesn't make things
clearer, and can make things horrendously slower.) 4) Starting a
performance critical tight loop from the middle.
ISTR some verbiage in H&S that the presence of a goto can hinder some
compiler optimizations.

There may be some weak older generation compilers for which that is
true. However, most modern compilers actually internally transform all
control structures to "if ... goto" anyways.
 
C

Chris Dollin

I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)

I've never had to use a goto in a parser; could you unpack the reasons
why you've wanted one? [email if it's likely to be wildly off-topic.]
 
J

Joseph Dionne

Chris said:
I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)


I've never had to use a goto in a parser; could you unpack the reasons
why you've wanted one? [email if it's likely to be wildly off-topic.]

As a *troll* I use goto often to increase execution speed, easing code
readability mostly in library utilities that I write once and never look at again.

Here is my general structure.

int func(arguments)
{
int error = 0;

/* lengthy function code listing */

/* at various "test" points in function the test below exists */
if (something_aint_right)
{
error = 1;
goto FINAL_func;
}

FINAL_func:
/* clean up any local resources, like malloc() calls, device opens, etc */

if (error)
{
/* any aditional code for error processing here. */
}

return(error);
}


This technique simple allows me to not code multiple in line error condition
tests, and give me the ability to immediately jump out when things go bad.
 
W

websnarf

Chris said:
I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)

I've never had to use a goto in a parser; could you unpack the reasons
why you've wanted one? [email if it's likely to be wildly off-topic.]

Well, I measure the performance of the code I write, and I have never
used/figured out yacc or bison or any of those tools. Most parsing
that I implement boil down to what I would call state machines with
counters. The gotos are for state transitions. The typical thing that
I've seen is a switch statement wrapped in a while(), but as I
mentioned switch is *extremely* slow as compared to a goto. Goto costs
the CPU almost nothing (at worst 1-clock of empty decode) as compared
to a break->continue->switch (essentially a goto, then a comparison, a
branch, then an indirect branch) which you pay for in the "well
structured" parsers.
 
C

Chuck F.

John Bode wrote:
.... snip ...


There may be some weak older generation compilers for which that
is true. However, most modern compilers actually internally
transform all control structures to "if ... goto" anyways.

The exception is machine architectures with special instructions
for a looping construct. This includes the HP3000, which has a
special 'for' construct, and the 808x6, which has a 'rep' (repeat)
construct.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
K

Keith Thompson

You can always use another control structure -- the question is whether
or not doing so makes the code more complicated or slower.

I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)

The typical cases where goto is useful: 1) when escaping from more than
one level of loop control, 2) when you have more than one "clean up and
return" code fragment that can be reached from even more scenarios
(typically "clean up and return error" versus "clean up and return
sucess".) 3) Any state machine (switch often doesn't make things
clearer, and can make things horrendously slower.) 4) Starting a
performance critical tight loop from the middle.

In the latter case, I'd probably prefer to use Duff's Device (with a
big fat comment block explaining why I really really needed to do
this).
There may be some weak older generation compilers for which that is
true. However, most modern compilers actually internally transform all
control structures to "if ... goto" anyways.

I actually don't know much about the *current* state of compilers, but
the one I worked on (not a C compiler) actually used higher-level
control structures in its intermediate code. A loop, for example, was
explicitly represented as a loop; this made hoisting more
straightforward. ("Hoisting" refers to taking an expression evaluated
inside a loop and moving its evaluation outside the loop.) Gotos were
allowed, but they would make the optimizer's job more difficult.
 
R

Richard Tobin

There may be some weak older generation compilers for which that
is true. However, most modern compilers actually internally
transform all control structures to "if ... goto" anyways.
[/QUOTE]
The exception is machine architectures with special instructions
for a looping construct. This includes the HP3000, which has a
special 'for' construct, and the 808x6, which has a 'rep' (repeat)
construct.

I think you're mixing up two separate parts of the compiler here. In
a typical modern compiler, the control structures will be converted to
linear blocks with jumps between them regardless of the target
architecture. If appropriate, some of those blocks will result in
generation of "rep" instructions in a later phase.

-- Richard
 
C

Christian Bau

Chris said:
I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)

I've never had to use a goto in a parser; could you unpack the reasons
why you've wanted one? [email if it's likely to be wildly off-topic.]

Well, I measure the performance of the code I write, and I have never
used/figured out yacc or bison or any of those tools. Most parsing
that I implement boil down to what I would call state machines with
counters. The gotos are for state transitions. The typical thing that
I've seen is a switch statement wrapped in a while(), but as I
mentioned switch is *extremely* slow as compared to a goto. Goto costs
the CPU almost nothing (at worst 1-clock of empty decode) as compared
to a break->continue->switch (essentially a goto, then a comparison, a
branch, then an indirect branch) which you pay for in the "well
structured" parsers.

One suggestion for a C extension:

continue <expr>;

which can be used within a switch statement: It evaluates the
expression, then repeats the original switch statement with the value of
<expr> instead of the original value of the switch statement. Obviously
this can be optimised to a simple jump instruction if <expr> is a
constant expression. Would that get rid of your goto's?

(This extension wouldn't break any existing code, since it is impossible
in the current C language to have a 'continue' followed by anything but
a semicolon).
 
C

Christian Bau

"Chuck F. said:
The exception is machine architectures with special instructions
for a looping construct. This includes the HP3000, which has a
special 'for' construct, and the 808x6, which has a 'rep' (repeat)
construct.

I bet good compilers will still _first_ translate everything into "if
.... goto" and _then_ find situations where special machine instructions
can be used. For example, cases where the x86 "rep" prefix can be used
are quite rare.
 
W

websnarf

Christian said:
Chris said:
(e-mail address removed) wrote:
I personally follow only one rule regarding goto: avoid using it unless
using it leads to either clearer code or faster (executing) code. This
rule alone is sufficient to make the use of goto fairly uncommon in my
code to the point of "spaghetti code" never being an issue. (If
there's one exception it would have to be parsers -- but in those cases
even the cleanest control structures don't actually lead to a clearer
representation of the parser.)

I've never had to use a goto in a parser; could you unpack the reasons
why you've wanted one? [email if it's likely to be wildly off-topic.]

Well, I measure the performance of the code I write, and I have never
used/figured out yacc or bison or any of those tools. Most parsing
that I implement boil down to what I would call state machines with
counters. The gotos are for state transitions. The typical thing that
I've seen is a switch statement wrapped in a while(), but as I
mentioned switch is *extremely* slow as compared to a goto. Goto costs
the CPU almost nothing (at worst 1-clock of empty decode) as compared
to a break->continue->switch (essentially a goto, then a comparison, a
branch, then an indirect branch) which you pay for in the "well
structured" parsers.

One suggestion for a C extension:

continue <expr>;

which can be used within a switch statement: It evaluates the
expression, then repeats the original switch statement with the value of
<expr> instead of the original value of the switch statement. Obviously
this can be optimised to a simple jump instruction if <expr> is a
constant expression. Would that get rid of your goto's?

Yes it would -- I think we've discussed this here before, and I
endorsed that or a similar change as well. But I can use goto and an
extra label today ... so, the value of this may not be extremely high.
 
R

Randy Howard

Christian Bau wrote
(in article
For example, cases where the x86 "rep" prefix can be used
are quite rare.

Not at all. Anytime you use memcpy() with a large len
parameter, it can be used to very good effect. memcmp() is
another.

However, I can't come up with a good example offhand for using
rep during goto or switch evaluation, but there probably are a
few.
 

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,776
Messages
2,569,603
Members
45,185
Latest member
GluceaReviews

Latest Threads

Top