Not really, I have deployed plenty of C code into production and never used gotos, other than special flavoured gotos like UNIX signals.
My problems have always been in how memory corruption friendly C happens to be, nothing to do with how to use structured programming practices for resource cleanup.
I don't see any similarity between gotos and signals at all. Gotos are just explicit jumps, while the "normal" structured way of doing jumps is to have them inferred from nested regions (that double as scopes and lifetime guards for automatic variables).
The structuredness of such inferred jumps usually is both sufficient and convenient, but sometimes being extremely structured leads to boilerplate and inefficiencies. That shows already with early returns from nested scopes, which aren't widely frowned upon, while they are very similar to common usage of goto. I would say I haven't encountered a goto that isn't basically an early return from some nested scope to after some parent or grand-parent scope.
In that sense, a goto can save from having to extract a nested scope as a stand-alone function just to write it as an early return. I would say that many gotos in the wild could be rewritten as early returns after making a standalone function, but maybe sometimes this is too much of a hassle, or, subjectively, puts a toll on readability.
Signals are implicit GOTOs in the sense of INTERCAL's COMEFROM.
As for structured handling, instead of gotos all over the place, do inverted conditions for early returns similar to what Swift has done with guard statement, embrace functions for resource cleanup, if the cost of a jump brings cold sweat, have them inline and called alongside a return, most compilers will replace calls with jmp opcodes.
> Signals are implicit GOTOs in the sense of INTERCAL's COMEFROM.
What?
> guard
How does it help to have an inverted if statement? Not sure what is the point, can do without.
Goto isn't necessarily for resource cleanup. The common usage is as an early break from the currently executed block, to what comes after the block. Which is often cleanup code, but not necessarily.
You clearly don’t understand the problem. Imagine all the ifs properly inverted like you want them to be. Good. Now imagine you have to free 6 allocations, close 3 FDs, and wait on a few threads before returning. Imagine you have 10 early returns. Your cleanup function would be an unreadably silly 10 arg thing with extra pointers everywhere and you have to call it 10 times. Thats insane boilerplate just because you cant stomach a local goto. Why not just goto cleanup, avoid the mess, save a bunch of time, and cleanup naturally and locally in the same function where everything is defined?
My problems have always been in how memory corruption friendly C happens to be, nothing to do with how to use structured programming practices for resource cleanup.