Damn Skippy said:
To me,
if ( a) { ... }
reads the same as
if (!a) goto skip_this; { ... } skip_this:
especially, and i will be flamed for this, if you consider the opcodes
which will be generated, on the actual real tangible machine(s) on
which it will run. When you think of it this way, it doesn't matter
whether you use goto or not, cos the CPU will (i.e. JUMP type of
instruction).
Most compilers are optimizing anyway, or at least become so with the
addition of options. gcc, for example, probably knows more about
opcode scheduling on Intel chips than I'll ever want or need to (how
to avoid cache misses, pairing rules, etc.), so I can trust it to
generate optimal code even if I give it human-readable C.
I think the impact of optimizing compilers plus the continuous
increases in chip speed negate the whole notion of manually optimizing
C in that way. If you need to speed things up, give the compiler a few
options. If you really need a speedup, choose a different algorithm.
As a last resort, hand-code some assembly.
So you must decide what is readable, and what other people will think
is readable. Bottom line - if people keep asking you why you have all
those 'goto' statements, it's time to cut back.
Of course, some people will flame you for having any goto statements.
Or break statements. Or subroutines with more than one return
statement. Or assignments. Or ...
Remember, C code will be:
1) compiled and executed or
2) interpreted or
3) in a textbook, hopefully with rules and exceptions
That's probably true, but you still can trust the compiler farther
than you seem willing to.
============ inefficient, inelegant, recommended ===========
Inefficient is relative: If a Pentium burns a few thousand clock
cycles on inefficient assembly, what have I actually lost? Less than a
second.
Inelegant is also in the eye of the beholder: I think the code below
is perfectly readable.
for ( .. ) {
if ( a != b ) {
good=false;
complain();
break;
}
}
if (good) {
process();
}
cleanup_regardless:
This label isn't referenced by anything yet. I don't know if that's
warnable, but it certainly looks odd.
cleanup();
============ better? saves one test and one stack variable ===========
Maybe on some machines with some compiler options.
And it isn't very structured: What happens when you want to change the
behavior of the code, perhaps add a test for some edge case in some
instances, instead of simply jumping straght to cleanup_regardless
every time? With a subroutine, you simply add a value you can pass in.
With a goto, you either duplicate code to check for the edge case
everywhere that needs it right before the goto (a very poor solution),
you use a global you check at the point you jump to (another poor
solution), or you add another label in your code and modify goto
statements (a third poor substitute for good planning).
for ( .. ) {
if ( a != b ) {
complain();
goto cleanup_regardless;
}
}
process();
cleanup_regardless:
cleanup();
============ ===========
of course, i hope i never see gotos in something like:
I don't think anyone is here to condone that. I think there would be
more people willing to defend the ALTER verb in COBOL than that mess.