Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » How bad is a goto statement?

This thread is locked; no one can reply to it. rss feed Print
 1   2   3   4 
How bad is a goto statement?
HardTranceFan
Member #7,317
June 2006
avatar

Before anyone thinks about flaming me, no, I don't use goto myself. This comment got me thinking about it.

Assembler (Z80) has various jump instructions, some conditional, followed by the memory location to jump to. These differed to a call instruction in that once you jumped, you couldn't return (the address jumped from wasn't pushed onto a stack, whereas the calling address was).

With this in mind, is it wrong to use the occasional goto in code, other than for aesthetic reasons?

--
"Shame your mind don't shine like your possessions do" - Faithless (I want more part 1)

Jonatan Hedborg
Member #4,886
July 2004
avatar

I have to admit that i have used in on occasion, when the alternative was to re-write a loop and add a bunch of variables and if's. Not in a large program however.

It's just very ugly and makes it hard to read the code

-------
Sweden: Free from the shackles of Democracy since 2008-06-18!

Richard Phipps
Member #1,632
November 2001
avatar

It's not wrong to use it were it is appropriate.

TeamTerradactyl
Member #7,733
September 2006
avatar

My ideas:

I would say GOTO is a BadThing for 99% of the cases; most programmers could code well enough to never need something like this.

I have seen a GOTO in a severely-nested function, though, which seemed to do alright. It was inside, I think, 8-9 while() and for() loops, and the point of the GOTO was "Okay, the value is now true/false. Continue with the rest of the current function!" Otherwise, he would have had to test on EVERY loop whether "done == true" (or whatever), and that was too expensive when you're dealing with a loop that was close to O(2^10) or something like that.

So my answer is that you should avoid it when possible, but if you HAVE to use it, do it only for efficiency reasons like that above.

You got C++? So if I got B-, I'm smarter than you?
He got hit so hard, he fell off the internet.
SOH CAH TOA: "some old hippie caught another hippie tripping on acid" - Jeff Bernard

Matthew Leverton
Supreme Loser
January 1999
avatar

In high level languages the use of goto can almost always be replaced by some other, more elegant solution. The only place in C where I ever use goto is to break out of some large nested loop. With some other languages, you can use the syntax break label; to avoid using a goto in such a scenario as that. Even in C, it's quite possible that such a loop can be better written as a function call that returns in place of the goto.

TeamTerradactyl
Member #7,733
September 2006
avatar

Matthew: I hadn't heard of "break label" before... That would be a useful tool if I ever start nesting... :D

You got C++? So if I got B-, I'm smarter than you?
He got hit so hard, he fell off the internet.
SOH CAH TOA: "some old hippie caught another hippie tripping on acid" - Jeff Bernard

Matthew Leverton
Supreme Loser
January 1999
avatar

Both Java and D use break label;. PHP uses break level;, where level is the number of loops of which you want to break out.

ReyBrujo
Moderator
January 2001
avatar

Goto makes programs hard to read and analyze. The only use for goto is to break from nested cycles, yes, but most times you can prevent that by adding control variables to each of the loops.

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Rampage
Member #3,035
December 2002
avatar

Goto can also be used to implement exception-like logic in languages like C. I remember having seen file access routines which had lots of potential failure points. Instead of repeating error handling code for each point, the routines used goto, which made them easier to understand. :o

-R

Goalie Ca
Member #2,579
July 2002
avatar

A goto is only bad because people get lazy. Most of the time a goto is not needed (mostly only needed in low-level). Without the goto statement c and c++ are turing complete. The danger is someone could use a goto and avoid deep thinking and proper organization of the code (create a proper state machine and code it cleanly!). This is when it becomes hard/impossible to read and debug.

-------------
Bah weep granah weep nini bong!

TeamTerradactyl
Member #7,733
September 2006
avatar

My question is this: If you use a GOTO to break out of a function, what happens to all the local variables? Are they taken out of scope, or can they still be accessed?

Oh, and I think I should start doing this from now on:

1int main(int argc, char **argv)
2{
3 string temp;
4 for (int i = 0; i < argc; i++)
5 {
6 temp = argv<i>;
7 if (temp == "--help")
8 {
9 goto HELP;
10HELPDONE:
11 }
12 else if (temp == "--version")
13 {
14 goto VERSION;
15VERSIONDONE:
16 }
17 else if (temp == "--screenResolution")
18 {
19 goto RESOL
20RESOLDONE:
21 }
22 else if (...)
23 }
24 
25 goto END;
26 
27HELP:
28 cout << "You asked for help...";
29 goto HELPDONE;
30VERSION:
31 cout << "You're asking for the version...";
32 goto VERSIONDONE;
33RESOL:
34 cout << "You're asking for the screen resolution...";
35 goto RESOLDONE
36 
37END:
38 return 0;
39}

EDIT: Fixed the labels per Simon Parzer's feedback. Thanks, Simon! :)

You got C++? So if I got B-, I'm smarter than you?
He got hit so hard, he fell off the internet.
SOH CAH TOA: "some old hippie caught another hippie tripping on acid" - Jeff Bernard

Rampage
Member #3,035
December 2002
avatar

In C goto can't take you outside the scope of the current function.

Quote:

Oh, and I think I should start doing this from now on:

Oh no! Don't ever do that! That's what the switch clause is for.

-R

Simon Parzer
Member #3,330
March 2003
avatar

Why don't you try it?

You got it all wrong BTW...

You do labels and gotos in C like this:

ThisIsALabel:;
//some code
goto ThisIsALabel;

I don't know exactly what you posted but I think the syntax is wrong.
In my opinion you should use goto where you need it. As long as you don't plan to share your code with others.
Sometimes it even makes code simpler. I mean, I rather have a bunch of gotos and three labels than five nested loops. When I started with BASIC a long time ago I got used to GOTOs and I have no big problems with them now.
In C++ or modular C the goto statement doesn't make much sense anymore, though.

HardTranceFan
Member #7,317
June 2006
avatar

Hey TT, your code put a grin on my face. ;D

--
"Shame your mind don't shine like your possessions do" - Faithless (I want more part 1)

orz
Member #565
August 2000

Sometimes, when writing my flow control, its difficult to implement it or think of it in terms of the standard C/C++ flow control primitives of for/while/do/switch loops and function calls. Usually in such cases I'll write what I'm thinking of in terms of loops and function calls, but do most of the flow control with if...break; and if...continue; statements and a few variables declared for the sole purpose of acting as flags for the loops.

Occaisonally though, the code will become harder to maintain, and/or debug if I write it that way, so I'll use goto statements instead. That has only happened maybe 10-20 times in the last 30 thousand lines of C/C++ code I've written, and some of those cases could have been expressed as exceptions more naturally if I hadn't been trying to avoid some issue involved with exceptions in the relevant code.

Even more rarely, sometimes I'll write something where I have such a difficult time even concieving of the flow control necessary that expressing it in terms of anything other than the natural flow control primitives I concieved of it in (often gotos for something like that) would take a great deal of diagramming and analysis and just be asking for trouble, so I write it as I concieve of it. That has only happened maybe 2 or 3 times in the last 30 thousand lines of C/C++ code I've written. Perhaps I should spend the time and effort diagramming and analyzing such cases; perhaps it would improve my ability to think in terms of the usual flow control primitives. But I'm not too sure about that. Perhaps that would merely limit my thinking to things that can easily be expressed in C/C++ instead.

Rick
Member #3,572
June 2003
avatar

I have never used goto in C/C++, and the only time I've ever used it is with VB 6 for error handling. Because I never use it, I never think about it, and therefore when coding, my mind never even considers it.

========================================================
Actually I think I'm a tad ugly, but some women disagree, mostly Asians for some reason.

Audric
Member #907
January 2001

Ladies and gentlemen, I give you: the computed goto in C.
The &&X syntax is a DJGPPism for : "the memory address of label X".

1#define AMC_GOTO_PCODE goto *pcode[*code_pointer]
2 
3 static const void * pcode[] = {
4 NULL,
5 &&AMCInt, // 1
6 &&AMCRegGlobal,// 2
7 &&AMCRegLocal, // 3
8 &&AMCRnd, // 4
9 &&AMCJump, // 5
10 &&AMCDirect, // 6
11 &&AMCExit, // 7
12 &&AMCIfnot, // 8
13 &&AMCIfjump, // 9
14 &&AMCIfdirect, // 10
15 &&AMCIfexit, // 11
16 &&AMCEnd, // 12
17 &&AMCAuto, // 13
18 &&AMCStore, // 14
19 &&AMCRecall, // 15
20 &&AMCStackup, // 16
21 &&AMCSpawn, // 17
22 &&AMCPause, // 18
23 &&AMCMove // 19
24 };
25 
26(...)
27// start of interpretation
28AMC_GOTO_PCODE;
29 
30(...) // some sample instructions :
31AMCInt: // put an Integer in the register
32 code_pointer++;
33 AmEval(&currentexp,code_pointer,*(code_pointer+1));
34 code_pointer+=2;
35 AMC_GOTO_PCODE;
36 
37AMCJump: // Jump
38 code_pointer++;
39 code_pointer= *code_pointer + BOB[Actor].programstart;
40 AMC_GOTO_PCODE;

Compared to a switch() statement, this was way cooler IMHO, and the emulation time went from 3% to 2% (precision of this figure is low, though)

Johan Halmén
Member #1,550
September 2001

I've never used goto. I do think it is a bad thing. The more you use goto, the more your code differs from what is considered typical C code structure. As Matthew said, you can put the part of code in a function and have returns instead.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This thread is obviously about nothing so heres a bunny with a pancake on its head. -kazzmir

TeamTerradactyl
Member #7,733
September 2006
avatar

Johan, I would agree with that, unless there has to be a lot of data transfer.

Say, for example, that you have declared a bunch of data at the beginning of your function. Then, you want to test whether "a == b" and "c < d" or "e != f", etc. If you push all that data into a separate function just to do the test, it slows down the code quite a bit.

If, however, you break out of a very-nested group of loops with a GOTO, you can continue with all the data and variables you had declared/changed/etc. as if you had simply "break"-ed a bunch of times to get there...

You got C++? So if I got B-, I'm smarter than you?
He got hit so hard, he fell off the internet.
SOH CAH TOA: "some old hippie caught another hippie tripping on acid" - Jeff Bernard

Kitty Cat
Member #2,815
October 2002
avatar

Here's some code I have for decoding macroblocks from an MPEG-1 data stream:

1static void p_picture(APEG_LAYER *layer)
2{
3 const int MBAmax = layer->mb_cols*layer->mb_rows;
4 int macroblock_type;
5 int coded_block_pattern;
6 int MBA, MBAinc;
7 int dc_dct_pred[3];
8 int PMV[2];
9 int bx, by;
10 unsigned int code;
11 
12slice_start:
13 dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
14 PMV[0] = PMV[1] = 0;
15 
16 code = apeg_start_code(layer);
17 if(code < SLICE_START_CODE_MIN || code > SLICE_START_CODE_MAX)
18 return;
19 apeg_flush_bits32(layer);
20 
21 slice_header(layer);
22 
23 bx = get_mba_inc(layer);
24 by = (code&255) - 1;
25 
26 MBA = by*layer->mb_cols + bx;
27 
28 bx <<= 4;
29 by <<= 4;
30 
31block_start:
32 code = show_bits(layer, 6);
33 
34 if(code >= 8)
35 {
36 code >>= 3;
37 
38 apeg_flush_bits8(layer, PMBtab0[ code ].len);
39 macroblock_type = PMBtab0[ code ].val;
40 
41 dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
42 
43 switch(macroblock_type & (MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN))
44 {
45 case MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN:
46 apeg_motion_vector(layer,PMV,forward_code,full_forward_vector);
47 apeg_form_f_pred(layer, bx, by, PMV);
48 
49 break;
50 
51 case MACROBLOCK_PATTERN:
52 PMV[0] = PMV[1] = 0;
53 apeg_empty_pred(layer->forward_frame, layer->current_frame, bx, by, layer->coded_width);
54 
55 break;
56 
57 default:
58 apeg_motion_vector(layer,PMV,forward_code,full_forward_vector);
59 apeg_form_f_pred(layer, bx, by, PMV);
60 
61 goto next;
62 }
63 }
64 else
65 {
66 apeg_flush_bits8(layer, PMBtab1[ code ].len);
67 macroblock_type = PMBtab1[ code ].val;
68 
69 switch(macroblock_type & (MACROBLOCK_QUANT|MACROBLOCK_INTRA))
70 {
71 case MACROBLOCK_QUANT|MACROBLOCK_INTRA:
72 layer->quantizer_scale = apeg_get_bits8(layer, 5);
73 // fall-through...
74 case MACROBLOCK_INTRA:
75 PMV[0] = PMV[1] = 0;
76 
77 apeg_decode_intra_blocks(layer, dc_dct_pred);
78 
79 apeg_fast_idct(apeg_block[0]);
80 apeg_fast_idct(apeg_block[1]);
81 apeg_fast_idct(apeg_block[2]);
82 apeg_fast_idct(apeg_block[3]);
83 apeg_fast_idct(apeg_block[4]);
84 apeg_fast_idct(apeg_block[5]);
85 
86 Move_Blocks(layer, bx, by);
87 
88 goto next;
89 
90 case 0: // Table 1 must have Intra and/or Quant flags set
91 goto slice_start;
92 }
93 
94 layer->quantizer_scale = apeg_get_bits8(layer, 5);
95 dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
96 
97 if(macroblock_type & MACROBLOCK_MOTION_FORWARD)
98 {
99 apeg_motion_vector(layer,PMV,forward_code,full_forward_vector);
100 apeg_form_f_pred(layer, bx, by, PMV);
101 }
102 else
103 {
104 PMV[0] = PMV[1] = 0;
105 apeg_empty_pred(layer->forward_frame, layer->current_frame, bx, by, layer->coded_width);
106 }
107 }
108 
109 coded_block_pattern = get_block_pattern(layer);
110 
111 do_block(0);
112 do_block(1);
113 do_block(2);
114 do_block(3);
115 do_block(4);
116 do_block(5);
117 
118next:
119 if(++MBA >= MBAmax)
120 return;
121 
122 if(show_bits(layer, 24) == 1)
123 goto slice_start;
124 
125 MBAinc = get_mba_inc(layer);
126 if(MBAinc != 0)
127 {
128 int i = MBAinc;
129 
130 dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
131 PMV[0] = PMV[1] = 0;
132 
133 do {
134 if((bx += 16) == layer->coded_width)
135 {
136 bx = 0;
137 by += 16;
138 }
139 apeg_empty_pred(layer->forward_frame, layer->current_frame, bx, by, layer->coded_width);
140 } while(--i);
141 
142 MBA += MBAinc;
143 if(MBA >= MBAmax)
144 return;
145 }
146 
147 if((bx += 16) == layer->coded_width)
148 {
149 bx = 0;
150 by += 16;
151 }
152 
153 goto block_start;
154}

It's pretty clear to see the code flow, IMO. 'goto block_start', and it goes to decode the beginning of a block. 'goto slice_start', and it goes to start decode the beginning of a series of blocks. 'goto next', and it goes to find the next block of the slice.

Compare that with a double nested loop (adding two more indentations to a good portion of the code), extra if checks, ambiguous 'continue' and 'break' commands, and needing to trace close brackets to see where something loops back to..

PS: Whee, having PMBtab0[code] in my code breaks the syntax parser. :D

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Billybob
Member #3,136
January 2003
avatar

Quote:

How bad is a goto statement?

goto jail;

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

tobing
Member #5,213
November 2004
avatar

We have managed to produce way over one million lines of C++ code with the only goto statements being in the various implementations of the quicksort algorithm. So I would advocate to not use goto, except when it makes algorithms easier to read, which is most often not the case. So, IF the algorithm is easier to read and understand using goto, then use it (but with great care!)...

Kris Asick
Member #1,424
July 2001

When I was still learning how to program I would constantly use goto. Especially when I was first learning BASIC because the gosub command didn't make sense to me.

Learning C/C++ eventually taught me why goto was stupid for most situations.

But, I do still use it, though only in one very specific situation: To restart a procedure. My goto statements always return an executing procedure right back to where it started, or as close as is necessary for the purpose at hand, thus eliminating the need to have multiple nested do loops or recursion.

Goto is generally avoidable, but in the uncommon chance that it makes your code MORE readable than a do loop or if statement, then by all means, use it.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

HoHo
Member #4,534
April 2004
avatar

Quote:

goto jail;

When I was coding in QBasic I used to have label for a part of code that printed some generic error message and exited the program. It was always called hell :)

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

raccoon
Member #7,478
July 2006

I think Sun has a good reason to not even include the goto-statement in Java.

 1   2   3   4 


Go to: