1

I'm not an expert in C but I do well, my main is embedded systems and microcontroller programming.

I know there's a myth of avoiding the use of the GOTO instruction because it creates spaghetti codes. As a Microcontroller programmer, I often use Assembler language for small programs and GOTO is the only way to go, but like in C (or unlike maybe?) one has to be careful when using the instruction because if you're in a subroutine for example, you probably have used a space in the stack memory so you can go back to the original routine.

But, if you mistakenly use the GOTO instruction to jump from your soubroutine to the main code then you didn't free the stack memory and if you call the subroutine several times you will eventually overflow.

So my question is, when we write in C a nested loop, a bunch of FORs for example, and we use the goto instruction to break from the inner loop, will that cause the same issue as I described before?

Daniel N.
  • 174
  • 1
  • 10
  • 4
    That's not possible. – Hans Passant Dec 13 '19 at 22:21
  • 7
    The question should focus on either [`GOTO` **in C**](https://en.cppreference.com/w/c/language/goto), which *cannot jump functions* (and thus cannot alter the stack or cause a Stack Overflow *itself*); or; focus on the 'equivalent' low-level assembly instruction which *could*. Consider updating the tags appropriately too. – user2864740 Dec 13 '19 at 22:23
  • 2
    Another possibility of achieving the same: https://stackoverflow.com/questions/23823277/is-a-goto-in-allocas-function-scope-valid – fukanchik Dec 13 '19 at 22:27
  • 6
    No, C's `goto` keyword can only jump to labels within the scope of the same function. Try it yourself and see what a compiler tells you. – Peter Cordes Dec 13 '19 at 22:27
  • 1
    lol, if that's so, I don't understand why so much hate against goto, yeah spaghetti codes, but honestly I think a bad programmer will do spaghetti codes regardless of using the goto instruction, and a good programmer can maintain a nice and neat code regardless of using or not the goto instruction – Daniel N. Dec 13 '19 at 22:34
  • @DanielN. If only that were not so brutally true.. (*In C*, GOTO is very useful for cleanup.. many people [like myself] use 'more sophisticated' languages on a daily basis though, some of which [needlessly] carry over a goto ;-) – user2864740 Dec 13 '19 at 22:36
  • @DanielN. That might be in theory how it should work, but in practice when `goto` isn't considered harmful it leads to messy spaghetti code. – Ross Ridge Dec 13 '19 at 23:01
  • 1
    The hate on goto is way overhyped. There isn't really anything wrong with goto as C has it. – fuz Dec 13 '19 at 23:01
  • 1
    @fuz Alternatively, there isn't really anything right with goto as Python doesn't have it. – Ross Ridge Dec 13 '19 at 23:03
  • 1
    @RossRidge Python (and many higher-than-C languages) also has sane ways of dealing with handling error cases. Consider a function in C, where one has to do a set of dependent operations (A, B, C, ..); where 1) successful operations must remain valid until the end of function; 2) the results must be cleaned up at the end of the function; including 3) if *any* of A/B/C/.. fail (in which case the function should also end early); This becomes *excruciatingly difficult* in C without goto-to-cleanup sections. – user2864740 Dec 13 '19 at 23:12
  • 1
    (Even C++ is much better here due to guaranteed object lifetimes; that's really the line between many languages and if goto fulfills a real useful role .. if state/object lifetimes are handled by a GC, have well-defined scope/ownership lifetimes, if there is support for 'using/with' constructs, or are entirely manual [as in C], etc.) – user2864740 Dec 13 '19 at 23:18
  • 5
    I suspect much of the "hate" dates to when other control structures were relatively new, but programmers were reluctant to adopt them (just like it took a while to convince programmers that high level languages could be used for system programming instead of assembly). So the language was overly harsh because goto was being used when `for` and/or `while` would be more appropriate. Now it's used sparingly, when other constructs don't fit, and that's OK. – Barmar Dec 13 '19 at 23:23
  • 2
    @RossRidge python has auto memory management, too, it's just magic. It's the reason you can pick up a python book and learn it in a week, all the stuff that used to be hard (pointers, memory management, exception handling) is magic. But at a dear, terrible cost. – TomServo Dec 14 '19 at 00:34
  • Which assembly language/instruction set has a GOTO instruction? – A.K. Dec 14 '19 at 01:49
  • @A.K. Thumb has `GOTO`/`B` which can unconditionally branch to non-local labels. – LegendofPedro Dec 14 '19 at 02:46
  • 1
    @A.K. The baseline of Microchip microcontrollers use the GOTO instruction. Other chips will use the GOTO with different names, JMP (jump AVR and MIPS), B (branch ARM), etc. Usually these chips will take stack memory to store the address of the PC counter (where the program was before it got interrupted) you can't come back to your main routine using GOTO unless you free your stack. – Daniel N. Dec 14 '19 at 04:53
  • As people said already - in C you can't do this with GOTO, in assembly you can do all sorts of damage if you don't use it correctly. This is kind of obvious. Incorrect usage of JMP is no different from an incorrect usage of any other instruction. You will eventually overflow the stack if you keep PUSHing without POPing the same number of bytes as you pushed. Regardless of whether you PUSH by using CALL without RET or some other weird coding. – tum_ Dec 14 '19 at 10:16
  • 1
    @DanielN.: MIPS's jump instruction is `j`. x86's jump is `jmp`. Most RISCs store a return address in a register, not the stack, and only if you use jump-and-link (MIPS `jal`, ARM `bl`); only CISC machines push the return address onto the stack for you (like x86 `call`) – Peter Cordes Dec 14 '19 at 13:09
  • Using branch or jump or goto instructions won't take stack memory, call will do, and ISR (Interrupt Subroutines) as well. The problem is using those instructions to return from a call or ISR. Stack in my understanding regardless of where is allocated means an arrangement of memory LIFO. The return addresses wherever they are stored, will have a fixed amount of memory so the overflow issue is still there. – Daniel N. Dec 14 '19 at 21:52
  • Now that I'm thinking maybe I should have posted the question thinking in recursive functions instead of nested loops, I think that's actually the equivalent scenario from ASM perspective. – Daniel N. Dec 14 '19 at 21:54

1 Answers1

3

goto can't be used to jump between functions, only within the same function. So it doesn't add to the stack, nor can it allow stack frames to be lost.

A more constrained mechanism that allows jumping directly into another function is setjmp() and longjmp(). But longjmp() can only be used during the lifetime of the function that called setjmp() with the same jmp_buf, and it's specified to unwind the stack to that function (the language specification doesn't actually refer to stacks, but uses more generic language, but it amounts to the same thing in most actual implementations).

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Note that `longjmp` doesn't do C++-style stack-unwinding; it skips destructors of any scopes it passes over. It really is just a context switch back to the `setjmp` callsite (restoring call-preserved registers including stack pointer), returning with the other return value. – Peter Cordes Dec 14 '19 at 05:20
  • 2
    @PeterCordes I didn't bother mentioning that because this question is tagged C. – Barmar Dec 14 '19 at 06:15
  • Oh right, yeah the other part of stack unwinding (restoring call-preserved registers) is covered by the state save/restore of `seg/longjmp` so there'd be no observable difference at all and my comment was pointless. I started writing it because the System V ABI used on Linux does specify `.eh_frame` metadata for stack unwinding even when compiling C, and it's non-optional so even `strip` isn't supposed to remove it. And because you used the phrase "stack unwinding"; that normally implies one frame at a time; I might use a different phrase here, like "reset" the stack to this context. – Peter Cordes Dec 14 '19 at 06:21