embedded software boot camp

C’s goto Keyword: Should we Use It or Lose It?

Wednesday, June 6th, 2018 by Michael Barr

In the 2008 and 2013 editions of my bug-killing Embedded C Coding Standard, I included this rule:

Rule 1.7.c. The goto keyword shall not be used.

Despite this coding standard being followed by about 1 in 8 professional embedded systems designers, none of us at Barr Group have heard any complaints that this rule is too strict. (Instead we hear lots of praise for our unique focus on reducing intra-team stylistic arguments by favoring above all else C coding rules that prevent bugs.)

However, there exist other coding standards with a more relaxed take on goto. I’ve thus been revisiting this (and related) rules for an updated 2018 edition of the BARR-C standard.

Specifically, I note that the current (2012) version of the MISRA-C Guidelines for the Use of the C Programming Language in Critical Systems merely advises against the use of goto:

Rule 15.1 (Advisory): The goto statement should not be used

though at least the use of goto is required to be appropriately narrowed:

Rule 15.2 (Required): The goto statement shall jump to a label declared later in the same function

Rule 15.3 (Required): Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement

Generally speaking, the rules of the MISRA-C:2012 standard are either the same as or stricter than those in my BARR-C standard. In addition to overlaps, they have more and stricter coding rules and we add stylistic advice. It is precisely because MISRA-C’s rules are stricter and only BARR-C includes stylistic rules that these two most popular embedded programming standards frequently and easily combined.

Which all leads to the key question:

Should the 2018 update to BARR-C relax the prior ban on all use of goto?

According to the authors of the C programming language, “Formally, [the goto keyword is] never necessary” as it is “almost always easy to write code without it”. They go on to recommend that goto “be used rarely, if at all.”

Having, in recent days, reviewed the arguments for and against goto across more than a dozen C programming books as well as other C/C++ coding standards and computer science papers, I believe there is just one best bug-killing argument for each side of this rule. And I’ll have to decide between them this week to keep the new edition on track for a June release.

Allow goto: For Better Exception Handling

There seems to be universal agreement that goto should never be used to branch UP to an earlier point in a function. Likewise, branching INTO a deeper level of nesting is a universal no-no.

However, branching DOWN in the function and OUT to an outer level of nesting are often described as powerful uses of the goto keyword. For example, a single goto statement can be used to escape from two or more levels of nesting. And this is not a behavior that can be done with a single break or continue. (To accomplish the same behavior without using goto, one could, e.g., set a flag variable in the inner block and check it in each outer block.)

Given this, the processing of exceptional conditions detected inside nested blocks is a potentially valuable application of goto that could be implemented in a manner compliant with the three MISRA-C:2012 rules quoted above. Such a jump could even proceed from two or more points in a function to a common block of error recovery code.

Because good exception handling is a property of higher reliabilty software and is therefore a potential bug killer, I believe I must consider relaxing Rule 1.7.c in BARR-C:2018 to permit this specific use of goto. A second advantage of relaxing the rule would be increasing the ease of combining rules from MISRA-C with those from BARR-C (and vice versa), which is a primary driver for the 2018 update.

Ban goto: Because It’s Even Riskier in C++

As you are likely aware, there are lots of authors who opine that use of goto “decreases readability” and/or “increases potential for bugs”. And none other than Dijkstra (50 years ago now!) declared that the “quality of programmers is [inversely proportional to their number] of goto statements”.

But–even if all true–none of these assertions is a winning argument for banning the use of goto altogether vs. the above “exception handling exception” suggested by the above.

The best bug-killing argument I have heard for continued use of the current Rule 1.7.c is that the constructors and destructors of C++ create a new hazard for goto statements. That is, if a goto jumps over a line of code on which an object would have been constructed or destructed then that step would never occur. This could, for example, lead to a very subtle and difficult type of bug to detect–such as a memory leak.

Given that C++ is a programming language intentionally backward compatible with legacy C code and that elsewhere in BARR-C there is, e.g., a rule that variables (which could be objects) should be declared as close as possible to their scope of use, relaxing the existing ban on all use of goto could forseeably create new hazards for the followers of the coding standard who later migrate to C++. Indeed, we already have many programmers following our C coding rules while crafting C++ programs.

So what do you think? What relevant experiences can bring to bear on this issue in the comments area below? Should I relax the ban on goto or maintain it? Are there any better (bug-killing) arguments for or against goto?

Tags: , , , , , , ,

52 Responses to “C’s goto Keyword: Should we Use It or Lose It?”

  1. Bob Paddock says:

    The goal of any good code is to be safe, reliable, simple, and understandable (readable).

    Adding multiple levels of nesting structures just to avoid goto fails the ‘simple’/’readable test by making the code more complex.

    Adding flags to avoid goto is not always an option on smaller embedded parts, there is simply not the memory.

    Limiting goto to baling on errors would be reasonable in most all cases.

    The argument about skipping constructors should be covered by compiler warnings. All warnings shall be treated as fatal compile errors.

    There is another use of goto completely missing from this discussion, that of computed gotos. See https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

    Computed gotos are used to write efficient (ie for small memory parts) byte-code interrupters and in OS’s such as Contiki http://www.contiki-os.org/ . Contiki is based on Protothreads http://dunkels.com/adam/pt/ , that uses computed gotos when it is available.

    While there are ways to do this without computed gotos speed and memory size suffer.

    This also brings up the hidden cases of machine generated code using gotos. The Ragel State Machine Compiler is a good example of this: http://www.colm.net/open-source/ragel/

    As long as reliability and safety do not suffer I disagree with an outright ban on gotos as in the real world we still must meet shipping and costs goals. Banning goto may force us into using a part with a larger memory, raising costs. We can not always stay in the nice clean academical world that has no real world consequences.

  2. Cliff Brake says:

    The Linux kernel uses goto extensively for exception handling. This discussion is interesting: http://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/

    Here is a typical example: https://github.com/torvalds/linux/blob/master/drivers/bluetooth/btmrvl_main.c#L725

    • ChrisH says:

      Having read the link on using goto in Linux kernel code and Linus comments: that is the clearest and best argument I have seen for banning goto! It also would suggest the Linux kernel could do with re-writing.

      I know several serious and highly experienced people who specialise in Sw analysis and validation who have looked at goto and say whilst it is not completely evil it is widely misused. They also tend to agree with Dijkstra and Writh. Linus just dismisses them with no evidence or serious arguments which is a worry.

  3. Daniel Heater says:

    For C, I’m in favor of relaxing the restriction to match MISRA-C for the reasons you point out.

    For C++, I think of exceptions as a more powerful (and more error-prone, ironically) way to express goto. I did work with one C++ runtime (ARINC-653 partitioned OS) that was a subset of C++ and did not support exception handling. In that case I would say we wrote “C+-” and I would apply the same goto rules as C.

    I can’t think of a reason to mix goto and exceptions in the same C++ codebase.

    As C++ keeps rapidly evolving (C++-11 and beyond), I think its becoming more useful to treat C and C++ as entirely different languages.

    • Julian says:

      Agree: If you’re writing C++, and you’re starting with C coding standards, you will need to review (possible removing rules which aren’t appropriate) and augment them if you want decent C++ coding standards. Applicability to C++ of C coding standards shouldn’t be a deciding factor.

      As for goto, Dijkstra in his original article: http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html seems to be mostly considering the abuse of goto in comparison to constructs like while loops or switch statements. He also seems to concede that ‘alarm exits’ is a reasonable use of goto. The dilemma seems really to what extent the programmer can be trusted not to abuse goto.

      To that end, I tend to prefer coding standards which educate the reader, so giving examples of acceptable uses of a primitive such as goto is valuable. I would suggest that reviewed justification for uses which don’t easily map onto those given examples may be a sensible precaution.

      The use of goto is also closely related to the subjective question of when it is appropriate to return early from a function. Sometimes it is, sometimes it isn’t. Forbidding early return, would make some code much less readable. However, a function with returns scattered throughout (to no obvious benefit) should ring alarm bells.

  4. Martin L. Buchanan says:

    Recommend keeping the present rule. It is simple to learn, simple to remember, and simple to apply in code reviews and code scans by tools. As Mr. Barr notes, there have been no complaints about the rule. The possible memory management inconsistencies conjectured in C++ code with goto could also occur in C, just with different constructs, such as malloc and free. As described more than 50 years ago, during the “structured programming” movement, any code with gotos can easily be refactored into code without gotos.

  5. Michael Simpson says:

    Personally, I oppose the use of goto, primarily because it leads to sloppiness in inexperienced developers, who find it easier than solving a problem in a more readable, maintainable, and less bug-prone method. I haven’t worked in an extremely memory-limited environment to know how a goto could save memory, but if that needs to be a necessary exception, I have no problem with that.

    I do have an issue with the argument of allowing it for better exception handling because it allows a behavior that cannot “be done with a single break or continue”. In rule 1.7.c and 1.7.d, you’ve already banned the use of a single continue and break (outside of a switch) statement, so why now allow a mechanism meant to duplicate the use of multiple break statements? The current BARR-C didn’t provide an explanation for the ban on break (I was in the habit of using them to break out of a for loop) and had to look it up, but once I understood the reason (the condition clause of the for statement should fully describe the reasons for exiting the loop), I agree with it. Unless you’re planning to relax the rules in 1.7 (and I would urge you not to do that), allowing the use of goto doesn’t make sense.

  6. Dan Tebbs says:

    At the end of the day, the engineer or team responsible for a successful design, needs to have a range of tools, and to understand the risk and reward of each tool. Sometimes as engineers we get tempted to think in absolutes such as no-goto = no-risk! I think everyone here agrees that goto is generally speaking a high-risk, low reward tool. However, outright banning has it’s own costs and limitations (despite lack of complaints). I see a very few (exotic?), cases where goto really is a better solution and the risk is manageable.

  7. Andrew Wolfe says:

    The one place that I have found goto to be useful is where an assertion fails or a timeout occurs that I want to cause a full software reset. On some processors, a goto address 0x00 is the only good way that I’ve found to do this.

  8. Eric Smith says:

    I’m in favor of allowing restricted use of goto in C, for exception handling, and for escaping nested loops. Avoiding use of goto for these circumstances leads to more complex, less maintainable code.

    Since C++ has exceptions, I oppose use of goto for that purpose in C++. However, it still is needed for escaping nested loops.

    In my opinion, future revisions of both C and C++ should add named loops, for use with break and continue statements.

  9. Glenn Hamblin says:

    I’m sort of inclined to allow the use of goto. It is just a tool in your toolbox. If you’ve ever done assembly language programming you jump all the time, which is essentially what a goto is.

    I do agree however that it can and does ruin brand new coders, and they’ll use it as a crutch and write awful code. I would like to see a rule that does not explicitly forbid the use of goto, but perhaps has a requirement to include a well-documented explanation of why it was used.

    My $0.02

  10. Bill Webster says:

    I think goto should be allowed (and possibly encouraged) for ‘exception’ handling, for the reasons given in the question.

    It should not be allowed otherwise, i.e. to implement an arbitrary branch. This was always the intent of the original Dijkstra dictum, which some people took too literally.

    I agree with one of the prior commentators, that C++ should be treated as a separate language, so C++ arguments should be dismissed.

  11. Mark Schaffer says:

    Hard absolutes, like “never using gotos”, are probably not the way to go. Sometimes goto is the best tool for the job. Since I doubt that C can accommodate all structured programming constructs, and since C lacks things like multi-level break-from-loop as well as try/catch, allowing for the possibility of using a goto when it is needed should be allowed.

  12. Stuart Rubin says:

    I’m skeptical of any argument that claims that code with goto statements will lead to more efficient (speed, code, memory) runtime operation. What a modern compiler does with your source code is its business, and is almost certainly more efficient than what you can do on your own with “tricks” in the source code. Stick to the number one priority: bug free code. Keep the rule!

  13. Bogdan Baudis says:

    The reason while there are no complains about this rule is most likely that any sane process provides for waivers to the adopted coding standard, allowing to relax certain rules in certain situations.

    My opinion is that there are many other features of C which should go away before ‘goto’ used in these carefully chosen situations.

    If one needs a safe high-level language there are many proven choices.
    However, The reason C persist as a choice in safety-critical is than many safety-critical applications have to live with strict hardware and timing limitations hard to achieve with higher-level languages.

    Large part of the strength of C is that is just one step above the assembly (or 1.5 if things like CLANG’s LLVM are to be considered as 1 step) and I do not think that there is much to gain to pretend otherwise and try to “safe” it.
    The underlying computing platforms are all GOTO after all and unless there is a complete revolution in the way processors are designed, this is the way to be. And this is reflected in C.

    There are ways to avoid goto in situations where there are better solutions and a decent coder usually does not even consider using goto most of the times. But dealing with errors with complicated muliple-nested if-else structures or flags or etc makes code LESS READABLE and this is a SIN.

    I have not heard for a long time about goto being a root cause of serious bugs in the modern code. But I hear people consistently complaining about if-elses going on many pages, nested switch statements and ad-hoc error flags.

    • Peter says:

      Coding standards and in particular, the use of goto will probably remain contentious for as long as C remains. I am not trying to suggest that my views are any more valid or any better than anyone elses. I do have over 20 years experience writing and reviewing embedded C code. Not all of it has been safety critical, but even non-safety critical stuff has to work (though targets are relaxed in terms of whether you can prove that it works).

      I’m broadly of the view that goto is an acceptable way of dealing with exceptions where allocated resources need to be cleaned up. The alternatives seem to be increased levels of if / else nesting, multiple return points (with the all resources allocated so far freed before each return point) or maintaining a series of flags – or special values on resource handles to indicate what has been allocated or stuff like do{}while (0); loops with breaks in them to effectively construct a jump from arbitrary point in the “loop” to the end of it. All of these mechanisms have been sources of bugs which I have had to trace over the years. I don’t remember ever having found a bug which was introduced with a goto statement.
      The author(s) of Linux Device Drivers (O’Reilly) argued that allocating resources in order 1 2 3 and freeing them in reverse order, allowing goto to jump to a point which would free resources successfully allocated – Yes I have already read your comment, Michael that Linux Kernel code is not necessarily good style from a safety point of view – I can see some sense in this argument though. This seems like a reasonable use of goto to me.
      I disagree with the idea that providing you are jumping forward in the same function it is OK. I have seen things like this:

      if (foo)
      {
      /* some code */
      if (bar)
      {
      goto exception;
      }
      /* some other code */
      }
      else
      {
      exception:
      /* to me this is an ugly way to run code if foo is false or bar is false */
      }

      Any views on setjmp / longjmp? I have only seen these used once (in a popular compression library). It would have been fairly trivial to bubble the error back using return codes (two levels of function call at worst as far as I remember).

      I am not much of a fan of exceptions as a language construct. I agree with the earlier poster who called for a mechanism to break out of a named loop as an alternative, though we already have one. It’s called goto.

  14. Greg Willits says:

    I come to C and embedded after many years of working with OOP in the desktop/server application level and following the likes of the Agile, XP, and “craftsman” gurus. I spent a lot of time studying readability, writing for clarify of intent, and a lot of other perceived values. This realm has a definite philosophy of “write for the human, not for the machine” until you prove you really need to optimize the machine.

    I find this to be in contrast to how many C programmers think (old and young). What I call a “legacy mindset” to optimize the machine and conserve every bit and every cycle. I’m old enough to have started on Apple ][ hardware, and even older stuff. So, I get where that culture comes from. And now, doing embedded, I understand there are still extremely tight environments. But…

    I created and have been maintaining an embedded C application with about 100,000 LOC for about 7 years now. So, not super big, and not super long, but certainly enough scale to have studied, experimented, and learned a few things (not many).

    I’m self taught, and certainly no C-scientist, and doubt I have any novel insight, but after considering all the options, I looked at the reality of my embedded environment. It has enough memory, it has enough speed. “Write for the human, not for the machine” has more value to my project.

    In my code, I’m in favor of goto for in very restricted uses for very restricted purposes based on the value it adds in key places to simplicity, readability, and clarity of intent. So, like others who have commented, I use goto for exception handling, with a very limited allowed construct. I allow one labeled exit point as the target for goto. One or more goto instances are allowed, but each must always go forward to the one same labeled point, and they must being going forward for the same reason. For me, the classic example is input validation. A function with a series of go/no-go tests where each failure exits using a goto to an exit point at the bottom of the function (and handle any wrapup details if needed). Flags, nestings, and other constructs I’ve tried just are not as clean, not as readable, and not as recognizable as a pattern.

    While I fully understand the logic behind “goto is never required,” frankly the same can be said for many features of many programming languages. Some have very rare, but useful purposes.

    I also understand the sentiment behind preventing spaghetti code by inexperienced programmers, but honestly, is the use of goto their/our worst sin as newbie authors? I don’t think so. Inexperienced programmers write difficult to manage code regardless of goto.

    In the end, I don’t see any reason to adopt an all-or-nothing position with goto. Education and experience is the key to all good code, and to appropriate use of all programming language capabilities.

    IMO, change the discussion to where does goto add real value (which of course depends on what you consider valuable), and start teaching newbies to restrict its use to those areas — just like you would teach newbies the appropriate places to use subclassing and patterns.

    • Peter says:

      Greg Willits,

      I agree with everything you say other than “I allow one labeled exit point as the target for goto.”

      Where I use goto at all, I use it like this:

      if ((handle_1 = allocate (one)) == NULL)
      goto bail1;
      if ((handle_2 = allocate (two)) == NULL)
      goto bail2;
      if ((handle_3 = allocate (three)) == NULL)
      goto bail3;

      /* process stuff here */

      free (handle_3);
      bail3:
      free (handel_2);
      bail2:
      free (handle_1);
      bail1:
      return;

      Compare this with doing the equivalent with nested if else… you’d be nested three levels before actually starting processing. Compare to multiple return points where you need to remember which resources to free at each return point. etc. With the goto method, the amount of code which is exercised in a given error condition is minimised. Most code is common to error and Ok conditions.

      Constructing a loop from goto is really bad. I think we can all agree on that.

  15. Tom McCormick says:

    Adage: Error handling code is the most error prone, and poorly tested, region of coding.

    Alternatively stated, when something occurs that influences nominal code path execution, real problems, far outside the severity of the initial issue, may result.

    Use of goto as an exception handler allows code design to minimize new code execution as the result of an atypical condition and therefore reduce the possibility of ancillary issues in the newly executed code. This increases code quality. The goto statement, therefore, should be permitted for use as an exception handler.

    Example

    Consider code to read a file into memory, process the data, and return some calculated value. Along the way, malloc() must be used. Of course, free() and CloseFile() must always be executed; regardless of any error handling. One possible way to write this using the goto statement as an exception handler is:

    DWORD ProcessFile(char* sFilename, DWORD* pdwValue)
    {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    DWORD dwFileSize = 0;
    BYTE* pbMemory = NULL;
    DWORD dwValue = 0;
    DWORD dwReturn = NO_ERROR;

    // Validate
    if (pdwValue == NULL)
    {
    // Error
    dwReturn = ERROR_INVALID_PARAMETER;
    goto ExitFunction;
    }

    // Open file
    hFile = OpenFile(sFilename);
    if (hFile == INVALID_HANDLE_VALUE)
    {
    // Error
    dwReturn = GetLastError();
    goto ExitFunction;
    }

    // Get file size
    dwFileSize = GetFileSize(hFile);
    if (dwFileSize == INVALID_FILE_SIZE)
    {
    // Error
    dwReturn = GetLastError();
    goto ExitFunction;
    }

    // Allocate memory
    pbMemory = malloc(dwFileSize);
    if (pbMemory == NULL)
    {
    // Error
    dwReturn = ERROR_OUT_OF_MEMORY;
    goto ExitFunction;
    }

    // Read file
    dwReturn = ReadFile(hFile, pbMemory, dwFileSize);
    if (dwReturn != NO_ERROR)
    {
    // Error
    goto ExitFunction;
    }

    // Crunch data
    dwReturn = CalculateSomething(pbMemory, dwFileSize, &dwValue);
    if (dwReturn != NO_ERROR)
    {
    // Error
    goto ExitFunction;
    }

    // Return calculated value
    *pdwValue = dwValue;

    ExitFunction:

    // Free memory
    if (pbMemory)
    {
    free(pbMemory);
    pbMemory = NULL
    }

    // Close file
    if (hFile != INVALID_HANDLE_VALUE)
    {
    CloseFile(hFile);
    hFile = INVALID_HANDLE_VALUE;
    }

    // Return
    return dwReturn;
    }

    The example may look rather peculiar, but note a few things about it:

    + Very little happens in any of the error cases. At most, the return value is set. There is not a lot of code to introduce errors. More specifically, code path execution of any exceptional case is highly similar to the nominal case. Errors in nominal code execution will more likely be caught during development.

    + All execution paths run through the cleanup code following the ExitFunction label. Consider this the finally{} portion of the exception handler. No matter what happens free() and CloseFile() are always executed. The possibility of resource leaks is reduced; particularly if malloc/free and OpenFile/CloseFile are habitually always added to code in pairs.

    Maybe it goes without saying, but an ASSERT(0); should follow every instance of assignment to dwReturn. These were omitted in the above for brevity, but their presence does not change any of the above points about the use of goto as a means of code quality improvement.

    • Greg Willits says:

      Thet’s exactly how I use goto (and the only way I use it), and what I was describing above. So, it doesn’t look peculiar to me 🙂

      • G Buc says:

        Agree with Greg and Tom – only use I envision of goto in C is for specifically cleaning up on error, freeing stray memory and returning with an error code. I guess this is why MISRA set the rule as it is.

    • Jim Kortge says:

      I generally do something equivalent, but using ‘do { /* all the stuff that could fail */ } while (0);’ with ‘break’ instead of ‘goto’ at each failure point.

      • Nick says:

        That is an interesting approach, Jim. But it isn’t immediately clear (at the top of the loop) that you’re loop is actually a poor man’s Try block. Furthermore, your breaks will not work if there is nesting within your do/while loop (as was stated up in the article)?

  16. David Cuddihy says:

    Goto is very useful in exception handling within nested blocks. Used only as an exception and as limited by MISRA-C it leads to clearer code and better error recovery. In this case pragmatism beats purity: Goto should be narrowly allowed.

  17. Joseph Schachner says:

    Personally I cannot remember having to use a goto in C, and we changed to C++ over 2 decades ago so we certainly don’t use goto now. That said, I am not sure I would vote to ban it, but it’s a close call. I feel one of the problems with goto is that if you’re reading the code and you see one, you know where it is and what label its going to. Fine. But if you’re reading the code and you see a label, you do not know where the goto is or if there is only one goto that goes to it. You don’t know if the goto is above you or below you. It’s a pain. So what can be done:
    1) limit the allowed uses of the goto – this has already been done. Same module, label must be below the goto.
    2) Alternatively: add a name to each goto, and add to a label one or more “comefrom” clauses, that have the name of the goto. To enforce use of this, a goto should only work to a label that lists its name in a comefrom clause. The benefit of this (should be clear) that when you see a label you will know all the goto s that are allowed to jump to it. That is very unlike now, now when you see a label you don’t know if only one or more than one goto goes to it.

  18. Nathan Blackwell says:

    Strictly for C, I’d vote for relaxing the rule with the restrictions you’ve described.

    goto statements can be useful for (and can simplify) end-of-routine cleanup, which helps with unhappy path handling.
    With the restrictions you’ve laid out above, gotos can lead to improved readability and simplified logic, as pointed out by Mr. Paddock above. Just because code can be refactored to function correctly without gotos doesn’t mean it’s the most efficient or most readable.

    Code reviews can aid groups with enforcing good goto usage. Thankfully, bad goto usage is easy to spot.

  19. Walter Molloy says:

    As we can see from the contributions above a good case can be made on each side of the use of GOTO.
    For what it is worth, I would support the use of GOTO for exception handling and enabling a single exit point from a function. Having said that, the use of GOTO should be strongly challenged at code review.

  20. Joe Ruf says:

    I’ll have to agree with Bob Paddock.

    I’ve found in over 35 years of embedded programming that the judicious use of goto statements in very specific circumstances, such as exception handling, can improve readability and efficiency, both code size and speed. I believe the MISRA-C standard has it correct.

    Having to add flags and enclosing if statements obfuscates the actual intent of the code and can be just as buggy when a later maintenance operation has to figure out all of the conditions that allow a section of code to execute. Well laid out code is simpler to maintain than “correct” goto free code when the only reason for a flag and layers of if statements is to avoid the goto statement.

    Mr. Dijkstra’s original letter talked about the excessive use of goto statements not any use.

    Adding C++ to the discussion confuses the issue, it is a separate language.

  21. Cj Chin says:

    In mathematics or control theory, we talk about linearity of a signal.

    When there is a discontinuity between two points, for example a square wave, what are the frequency components which make up this signal? They would be in harmonics of the frequency of the square wave which stretch to infinity (ideally).

    Similarly, in a goto statement, we can talk about sequentiality of the code, and the bandwidth is our mind, our mind is capable of dealing with linear sequences and breaks in sequentiality is when we start to lose track and get confused. The further the break and the more it is interleaved in other sequences of code is where mistakes will be made more easily.

    The bottom line is: Linearity is to sequentiality, where bandwidth of a system is the limit, the system is our mind, Goto statements injects high frequency disturbance to the system, the mind, and hence the mind requires high bandwidth to keep track/maintain/read the code.

    Our mind is not dependendable all the time and not only this, the original author may not even be the same person maintaining the code in the future(which is usually the case). It is even more difficult for others to keep track of discontinuous breaks in the code

  22. Ashleigh says:

    My preference is to ban the use of goto.

    My internal coding standard (which I wrote over 25 years ago, and which bears a strong resemblance to yours) bans goto.

    (Arguments about linux kernel and exceptions are I think a different case not generally relevant to bug-busting in embedded systems.)

    I have not had or felt the need for using goto for many years writing very complex code, including many simple time based schedulers with multiple cooperating tasks.

    The first time I came across goto recently was in some code I had to adapt. This code was (is) an exemplar of bad practice. Imagine taking the Barr standard and inverting the logical state of every rule, so every “shall” became a “shall not” and vice versa. No useful comments. No useful naming. Crazy use of type names (if at all). Pointers all over the place to obscure structures overlaid by use of unions with no sensible context. Gotos jumping all around the place. Some names exported from code units (and some not). Cross-module calling all over the place without relevant header files being included. Disentangling this mess was near on impossible, I binned it and re-wrote it because in porting / adapting I would otherwise own all problems in this stinking mess. Better off starting again.

    That exercise reinforced to me that when you give ground on things like “goto”, there will be some clown who takes the liberties literally and uses goto with abandon.

    Mind you – my coding standard also has a get-out clause: All rules in the standard can be broken, provided there is a very good explanation given in comments in the code. Pragmatism needs to be permitted, but if you must break the rules you must explain why and it must be in the code for anyone else who maintains it to see.

    • Michael Barr says:

      Thanks for these comments. I can’t even imagine the horror of a program that breaks all the rules!

      BARR-C also has a procedure for deviation with a rule in a particular function or module.

  23. Stanford P. Hudson says:

    I am in agreement with Michael Simpson. It leads to sloppiness in inexperienced developers. The goto keyword is too powerful of a construct. It enables a programmer to jump anywhere at anytime without consideration of the next programmer who may need to add additional code. I personally adhere to the guidelines of providing a single exit from any block of code. This means no goto’s and no multiple returns from a function, no matter how many closing curly braces. There are exceptions to this: a break or continue statement within a while- or for-loop, for instance. I do not think goto’s should be outlawed, but they should be avoided.

  24. Eric Roesinger says:

    Bob Paddock rightly points out that clarity wins: this is often the sole justification to choose any programming language construct over another, though I still encounter performance issues specific to a tool chain requiring a surprising solution, from time to time. (E.g., the ARMCC ‘switch’ boilerplate has been a frequent offender in some execution “hot spots” I’ve had to mitigate.)

    I have on occasion designed (small!) finite state machines that were far more clearly implemented using ‘goto’ to implement transitions: these have almost invariably boiled down to a series of entry actions (sometimes guarded) followed by first a blocking operation, then a series of zero or more guarded transitions and finally one unguarded transition (usually to the same state).

    Even maintaining a state variable (eliminated by the choice of language construct) would only have obfuscated behavior of the code, which typically fell naturally into an odd number of columns (labels and braced pairs of optional guards and actions or transitions). In such cases, ‘else’ conditions were ordinarily absent; and “falling through” past a label was best forbidden—even such a default transition was clearer with an explicit ‘goto’ (which even the most primitive, “peephole” optimizer can elide), and this also allowed reordering of states during editing, for convenient reference.

    The code would typically come to resemble a state-transition table, e.g.:

    start: goto idle;

    idle: { { indicator(IDLE); } { if (...) goto stop; } { if (...) goto wake; } { } { goto idle; } }
    wake: { { delay(100); } { if (...) goto stop; } { if (...) goto busy; } { if (...) goto idle; } { goto wake; } }
    busy: { { indicator(BUSY); } { if (...) goto fail; } { } { if (...) goto doze; } { goto busy; } }
    doze: { { delay(100); } { if (...) goto fail; } { if (...) goto busy; } { if (...) goto idle; } { goto doze; } }
    fail: { { indicator(FAIL); } { } { } { } { goto stop; } }

    stop:

    Not necessarily the most common case—indeed, worth the trouble of a written deviation—but it does tend to be one of the cases where an absolute ban can do more harm than good. By the same token, when all the same guard conditions needed to be evaluated in a fixed, priority order (a more “orthogonal” case), I’ve seen such machines be better implemented in a loop driven by a local message pump and a table of entry handlers and successor states.

    In a similar vein, I don’t personally favor adding auxiliary variable tests to loop control blocks solely to avoid a ‘break’ or ‘continue’ handling a comparatively very rare occurrence: if these conditions are few and infrequent, doing so may both obfuscate the code and exacerbate a “hot spot” where the auxiliary test almost never terminates iteration.

    On a related topic, consider the lack of ‘break’ in Duff’s Device and the burden of banning it when an explicit, partially-unrolled loop is actually needed—e.g., a case where I once had to set up a loop in a supervisor rootine but execute each, unrolled iteration (terminating each at a particular bound due to a peripheral’s bus interface) in an ISR driven by a software PLL built around a timer-compare interrupt.

    Note, though, all of these cases need exceptionally clear documentation as well as rigorous justification. The difficulty is writing rules that preclude being “clever” in ways that merely obfuscate, without turning the corner cases into abstruse, nonperformant, unmaintainable nightmares.

  25. Eric Roesinger says:

    One other note: the use of ‘goto’ that is hazardous in C++ is generally that of jumping *into* a block from outside—which happens also to violate one of the *required* MISRA restrictions.

    I’ve seen compilers handle jumping *out* of a C++ block correctly, with regard to constructors; but this may be an artifact of their exception handling support.

    My inclination would be to prohibit using ‘goto’ as a substitute for exceptions where they are available: if they aren’t allowed to propagate across functions, much of their run-time and stack-space cost can be eliminated because the compiler knows all execution paths between ‘try’ and ‘catch’ within the same, enclosing block of a function.

    Obviously, this means they remain available to emulate exception-like flow in C and to cover the (very) few non-exception cases in which they remain clearer in both C and C++.


    egr

  26. Kevin Kilzer says:

    I support relaxing the restriction, particularly for exception handling as explained by Paddock and Heater. Another case where limited use should be allowed is to exit nested while/for loops, where ‘break’ in the inner loop would require flags to exit the outer. I would support banning goto into lower-level, nested blocks.

    Side story: I once had a colleague that would begin every program with a .h file that includes:

    #define repeatFrom goto
    #define continueWith goto

    He would create single functions of 1000 or more lines, but was meticulous to use the correct form if he was branching backwards or forwards to avoid getting lost in his own code. This construct passed the quality assurance team (who routinely forbid the use of goto), because you could grep the file and demonstrate that no goto’s were ever used! He had a number of other quirks as well.

  27. Adrian Jones says:

    I would take the view that gotos should not be used. If a piece of code requires a goto then a clear explanation/exception must be provided and during peer review this is considered. If the reviewer(s) agree then the got can be permitted otherwise the reviewer(s) will demand a re-write.
    For me personally in over 30 years of embedded C I have rarely required the goto – but it is a tool that is occasionally useful and as such I wouldn’t want it removed from my toolbox.

  28. Kevin Cameron says:

    If you are going to use C you might as well use “goto”, better still is computed-goto

    https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

    Everything in C has a purpose, you just need to know when to use, and when not. The goto is essential when you use C as an intermediate language for compiling DSLs.

  29. Carol Batman says:

    I agree with the limited use of “go to”. Particularly in limited RAM/ROM environments. Maintaining someone else’s code where a “go to” is used to a common exception handler is much easier that some of the convoluted means done just to avoid using a “go to”. When counting ROM bytes, it also can be more ROM-efficient.

  30. Steve H says:

    Though I never use goto, I recommend relaxing the ban on goto statements and allowing restricted use. A clause can be added banning its use in C++ class constructors and destructors as well as C module initialization code.

    While deeply nested code is difficult to read, breaking out of two level deep nesting is a common occurrence and careful use of goto effectively makes this clearer. The compiler can manage the stack, and it’s very easy to add coding errors and obfuscation as a result of crafting the logic to fall out of an outer nesting level. This is especially true in the maintenance phase as defects are fixed and features are added.

    Obviously any variables accessed beyond the goto label must be initialized within a reasonable range of values, and that information should be provided within a comment. These variables should be declared and initialized at the top of a function. It may make sense to only allow one goto label within a block or function, and that label must be below any goto statements.

  31. Bill Webster says:

    I’ve already stated my opinion that goto should be allowed for error handling. After reading more replies here, I’d like to add a couple of thoughts.

    Well written code clearly expresses its intentions.

    The obvious way to think about a process is how it will normally proceed. “How it will normally proceed” is also almost always the clearest way to describe a process. Hence all that C sample code with “Error handling omitted for the sake of clarity” caveats.

    Most modern high level languages provide native exception handling. Intent may be expressed more clearly by distinguishing normal flow from exceptional conditions. It’s a more expressive paradigm, which allows code to be designed more easily and to be understood more readily.

    C does not support exception handling natively. Anyone developing in C, who also uses a language that does support exceptions, will appreciate the expressive loss.

    The C goto statement can be used in a manner that (very partially) compensates for the lack of exceptions, with similar expressive clarity. In particular, it can be used to implement RAII in an obvious way. The alternatives, such as deep nesting, multiple flags, or duplicated cleanup code lead to code that is more difficult to reason about.

    I think the overarching principle should be: If avoiding goto results in code that is more difficult to understand, then use goto.

    Given that goto can also be used in Dijkstra’s “harmful” ways, a coding standard needs to delineate acceptable / non acceptable uses. A couple of rules that spring to mind are “only forwards” and “only to a label in the current block or an enclosing block”.

  32. Tarjei Knapstad says:

    While I dislike and try to avoid gotos, the one accepted use seems to be for error cleanup at the end of a function which does multiple resource allocations which may fail at some point. The blog post here illustrates this nicely: https://web.archive.org/web/20131231060301/http://onlinehut.org/2011/10/goto-is-not-evil-okay/

    I think MISRA has found a sensible middle ground here and that the “don’t use goto ever” rule is too strict.

    In C++ exceptions should be used for the above scenario.

  33. Matt Brossett says:

    I vote in favor of allowing the use of goto but with in compliance with MISRA guidelines. Although I have never written C code using the goto keyword, I have recently discovered its use in source code of libraries I have used. One notable library is mbedTLS, which is used for implementing security protocols to secure webpages and send secure email, etc . The mbedTLS uses the ‘fail’ and ‘exit’ labels at the end of most functions to log/print errors and release memory. It is used like the Try-Catch-Finally blocks in higher level languages like C#. I think the code is much cleaner and easier to follow than if the gotos were not used.

    Regarding the use of goto in C++ possibly jumping over constructors and destructors, couldn’t a similar thing happen in C if dynamic memory is used and one jumps over the alloc() or free() function? Such as in the mbedTLS library? Pointers in general can be dangerous if not used properly, but we should not ban their use altogether, but rather limit how they are used to prevent the errors. I think the same should be done for goto – limit the use but not ban it completely.

  34. Chris Tapp says:

    Personally, I like the MISRA approach (declaration of interest – I’m one of the authors). It is a bit more difficult to get exactly the same effect in BARR-C as it does not provide the deviation and guideline re-categorization that MISRA has. These two aspects allow the restrictions placed on the use of ‘goto’ to be controlled on a per-project basis.

    Firstly, R.15.1 is an advisory rule “The goto statement should not be used”. At the published enforcement level (advisory), the programmer is advised not to use goto, but there is no requirement for a formal sign-off (deviation) if it is used. However, a project may re-categorize the rule as required (meaning formal deviation is required if it is used) or as mandatory (goto may never be used).

    If R.15.1 is enforced at the required level, programmers are required to obtain official approval for the use of ‘goto’ through a deviation process that is part of the formal software development process used by the project.

    There are two other MISRA rules that control the use of ‘goto’ when R.15.1 is enforced as required or advisory. R.15.2 prevents ‘goto’ from being used to construct unstructured loops with the use of back-jumps. R.15.3 limits the complexity that can be introduced by the use of ‘goto’. These rules are both required and must therefore be enforced at that level or as mandatory – this means violation of these two rules, if permitted, requires formal approval.

    A fourth MISRA rule should also be mentioned – R.9.1 prevents a forward jump from jumping over the initialisation (by an initialiser or assignment) of any automatics. This is similar to a jump skipping a constructor call in C++, except that this is a constraint violation requiring a compiler diagnostic to be issued.

    The “computed goto” is a more difficult one to deal with as it is a language extension. MISRA restricts the use of extensions (R.1.2) and does not give specific guidance on its use.

    Trying to restrict the use of goto to a particular use-case (e.g. “exceptions”) is also tricky to do within a coding standard that is to be tool enforced – it is easy for a human to understand the intent of code, but this is not something that a tool can do without being given some additional information (e.g. annotations).

  35. David Albert says:

    How do you perform a soft-reboot/soft-reset without goto? I suppose, for example, in the ARM library, for Cortex M0 and M3 devices, you could use the CMSIS function:
    NVIC_SystemReset(); // restart from main()… (no return)
    But isn’t this just an implied “goto”? Or a special case of exception handling?
    In my applications, this is the perfect time to use a goto, since you are purposefully disrupting the normal program flow. And you’re not jumping to another forward-referenced label in the same block of code.
    So my vote is to keep the goto, with the caveats

  36. Matthew says:

    Like others my own internal coding standard written 22 years ago is very similar to BARR-C, with some exceptions that have lent towards MIRSA-C.

    I concur with Ashleigh and Michael that use of a “goto” should be documented as to the reason why this was found necessary to use at this point and what problem were they trying to solve.

    There are very few times now where the programmer needs to give instructions to the compiler on how best to optimise the code, which in reality is the crux of the problem many try to solve with it’s use.

  37. Edgar Holleis says:

    I recommend the use of goto for exception handling in C, that is branching DOWN and OUT of nested blocks. It is simply the most explicit and most clear way of achieving that. I am not a fan of flags (which forces control flow into data). I am also not a fan of complicating loop conditions. Goto is the lesser evil.

    As for bug-avoiding: Even if goto is used for branching DOWN and OUT, it may still happen that you jump over initializers leading to use of un-initialized variables. I’ve witnessed “gcc -Wall” (4.4.7) failing to print a warning in such situations. I hope that gcc and other compilers have improved since. Under that assumption I think using goto for exception handling is a net win for quality.

    C++, on the other hand, has richer control flow statements. I don’t think goto is ever a win for C++.

  38. Nick says:

    What recommending goto usage be restricted to error handling macros, and then defining a rudimentary template as a starting point?

    Example:
    #define THROW_EXCEPTION(EXCEPTION_NAME) (goto EXCEPTION_NAME)
    #define CATCH_EXCEPTION(EXCEPTION_NAME) EXCEPTION_NAME:

    This would at least make it really clear that this usage of goto is intended for an extremely narrow. This is just a starting point too. You could extend this to generate switch statements at the end of a function to handle multiple exceptions, and set a flag in the “THROW_EXCEPTION” macro. Then have a “TRY” macro that defines that flag holding local variable.

    Relaxing Rule 6.2.c. “All functions shall have just one exit point and it shall be at the bottom of the function.” should also be reconsidered for the same reasons as goto. If I don’t have any cleanup to do I can do all of my exception handling immediately after the problem has been detected and get out of dodge.

Leave a Reply to Peter