Exactly. Sometimes it's just clumsy/tedious to *not* resort to a goto.
OTOH, too tolerant an attitude towards them tends to result in code that gets tangled and gnarly. If I find myself "needing" to resort to a goto, it forces me to rethink the way I have built the algorithm.
OTOOH, note how often I "broke" MISRA rules in that code fragment. Rewriting it to consolidate all return's to a single point would have resulted in a real tanlged mess. Then, going back and removing the break's... etc.
Simply because it is too easy to fall into the "routine" of resorting to goto to fix the structural errors in your code. IMO, it's a case where you *discourage* its use but never
*forbid* it.
It's *easy* to hit 4 levels of indent in the body of a non-trivial function. Wrapping clauses in function calls just muddies the waters for the sake of eliminating an indent level. E.g.,
gobble_leading_zeroes( char **ptr // IN/OUT references pointer to digit string ) { p = *ptr while (*p == 0) p++
*ptr = p }(or equivalent)
I rely on the "shape" of my code on the "printed" page to convey a lot of information about it's structure. And, I *obsess* over whitespace (there's never enough!).
E.g., the axiom that "a function should fit on a single page" just doesn't work for me -- unless you let me run the monitor in portrait orientation! :>
But that's the point!
"if ((*ptr != 'e') && (*ptr != 'E'))" is the opposite of "if ((*ptr == 'e') || (*ptr == 'E'))" and, IMO, is easier to relate to than prefacing the latter with '!'
I.e., "if it's not an 'e' and it's not an 'E', either, THEN..." instead of "if it's not: (an 'e' or an 'E') THEN..."
Use these equalities to express things in easier terms with which to relate.