embedded software boot camp

Goto heresy

Monday, February 1st, 2010 by Nigel Jones

Today’s post is prompted by an email I received from Michael Burns. With his permission I have reproduced his email below.

Hi Nigel,

What is your opinion on the usage of goto in C?

Sometimes when a routine has many conditions [usually for error handling] I have used a do {..} while(0); loop with breaks thus avoiding both deep nesting and repeated checks with a status variable.

For example:

unsigned int XXX_ExampleRoutine (unsigned int XXX_instance, unsigned int *XXX_handle)
{
unsigned int status;
do
{
if (!XXX_IsValidXXXInstance (XXX_instance))
{
status = XXX_INVALID_INSTANCE;
break;
}
if (XXX_handle == NULL)
{
status = XXX_INVALID_ARGUMENT;
break;
}
status = XXX_AddRequest (XXX_instance, XXX_handle);
if (status != XXX_STATUS_OK)
{
break;
}
etc
} while (0);
return status;
}

But perhaps the do {..} while(0); loop is just an excuse not to use goto?

My (slightly edited) response to him was as follows:

I rarely use a goto statement. While I dislike them for their potential abuse (for example a number of years ago I looked at a Flash driver from AMD that was absolutely littered with them), I also think they have their place. Furthermore I think folks that scream ‘the goto statement is banned’ and then happily allow the use of ‘break’ and ‘continue’ are deluding themselves.

Turning to your example code. As you have pointed out, coding this without using ‘break’ or ‘goto’ can rapidly lead to code that is a nightmare to follow. Indeed once one gets beyond about four or five tests of the type you are performing, I’d say that the code becomes impossible to follow unless you use either the style you have espoused or a goto statement. I’d also make the case that in this situation a goto is actually better. To illustrate my point, I have modified your code slightly, in much the way someone might who wasn’t paying attention:

unsigned int XXX_ExampleRoutine (unsigned int XXX_instance, unsigned int *XXX_handle)
{
unsigned int status;
do
{
if (!XXX_IsValidXXXInstance (XXX_instance))
{
status = XXX_INVALID_INSTANCE;
break;
}
if (XXX_handle == NULL)
{
status = XXX_INVALID_ARGUMENT;
break;
}
do
{
status = XXX_AddRequest (XXX_instance, XXX_handle);
if (status == XXX_STATUS_BAD)
{
break;
}
} while (status == XXX_SOME_STATUS);
etc
} while (0);
return status;
}

In this case, the break wouldn’t work as desired, whereas if you had coded it with a goto, the code would still work as intended.

I guess the bottom line for me is that K&R put a goto statement into the language for a reason (while leaving out lots of other features). Like just about everything else in C, the goto statement can be abused – but when applied intelligently it has its place.

In his reply Michael commented that MISRA doesn’t allow goto or continue, and limits break statements to loop termination. I’ve already posted my comments on MISRA compliance – and I think my position here is consistent with what I wrote then – which in a nutshell is this. MISRA compliance is all well and good, but when it prevents you from implementing something in the most robust manner, then I think it’s incumbent upon one as a professional to do what is best rather than what has been mandated by a committee. If that includes using a goto, then so be it.

Home

25 Responses to “Goto heresy”

  1. Mans says:

    Thank you for this. I have always thought of this bizarre use of the do while(0) to sneak in a goto without saying the word as highly hypocritical.Regarding MISRA, my opinions are not printable.

  2. Gauthier says:

    There is a good number of gotos in the source code of the linux kernel.A discussion about that:http://kerneltrap.org/node/553/2131Torvalds is not really nuanced, but he seems to think in the same direction as you.The problem being that if goto had not the reputation it has, some (many?) people would be overusing it in place of good structure.My take is that goto is fine, but only if it is adding value, never the default choice.Break and continue, same thing.It turns out that I use them very rarely.Another issue: if there are gotos in a source, someone new to the code might start using it without care. After all, if others used goto, they might as well…The tool is ok, but how do you prevent it from reaching the many wrong hands?

  3. Nigel Jones says:

    Gauthier – an interesting observation about the Linux kernel – I was not aware of this. Concerning 'goto' being a tool that may fall into the wrong hands. I guess my opinion is that you could pretty much make the same case for the entire C language. Indeed wasn't that one of the main arguments for the development of ADA?

  4. Mans says:

    Gauthier: That is what code reviews are for. Anyone new on a project should have his/her code reviewed by someone with more experience. The experienced programmer should of course also be subject to code review.

  5. Kyle Bostian says:

    Nice post as usual. Regarding: "MISRA doesn't allow goto or continue, and limits break statements to loop termination." I don't have a copy of the MISRA standard, but my understanding is that MISRA allows breaks in switch…case constructs. Whether that is in addition to loop termination, or instead of loop termination, I don't know.

  6. Travis says:

    If I understand correctly, the core of the argument against goto (in Goto Considered Harmful, and similar) is that the keyword allows the program to branch willy-nilly and the resulting program flow becomes fractured and difficult to follow and test.I agree with this, and my use of goto is usually limited to the type of error handling code in this post–typical of what would be done with a try…finally exception handler. But, following that argument, any use of break, continue, or (more diabolically, longjmp) should also be banned.Use the appropriate tool for the job; goto is sometimes the perfect solution, and when used properly, and restricted in scope inside a function of appropriate size, it really doesn't make things the logic or program flow more difficult to follow than any other operator that breaks the linear flow of the program.

  7. Anonymous says:

    I think goto's have their place (especially to break out of a function prematurely, where a little bit of cleanup might be required before returning).Quite often, though, people seem to use a goto to do immediately to a return statement (in which case why didn't they simply return from the place they were?). The only possible justification for this, is that some coding standards require (for simplicity, presumably) that each function has a single return point. Of course, as per your discussion above, I'm not sure that hacking unnecessary complexity simply to fulfill this requirement is quite within the spirit of the task….

  8. Gauthier says:

    Another point of having a goto to a return at the bottom of the function is if you want to add some functionality in all cases before return.For example deallocating memory.mem allocgoto end if error//stuffend: mem deallocreturnMaybe you don't need it right now, but having the construct ready might help for the future. I definitely agree that this is questionable.Early returns is also a hot topic, if not as wild as gotos. They break the flow as well as gotos do. However, it feels like coders against early returns would also be against gotos.

  9. Nigel Jones says:

    I'm intrigued that at least so far there appears to be general support for the judicious application of goto. I was expecting to be told by at least a few folks that I was a menace to society / a great example of why EE's should never be allowed close to a compiler. I'm not sure if the readers of this blog are inherently self selected – and thus more likely to find my opinions agreeable, or whether there is indeed broad support in the industry for the limited application of goto. If it is the latter, then the implications for most coding standards are indeed interesting. Perhaps future commenters could mention whether their company coding standards allow goto or not?

  10. Mans says:

    The last company I worked at (I'm independent now) had a rule against goto. I used it from time to time when I though it right regardless, and got away with it.I see coding standards as a crutch designed to enable poor programmers to produce code that doesn't blow up immediately. That does not mean they'll be producing good code. In fact, some of the worst code I've seen was written by people religiously adhering to coding standards.This is unrelated to, but often confused with, style guidelines. When working with others on a project, it is generally a good idea to use a common style (indentation etc.) instead of everybody using his/her personal preference. I find that I quickly adjust to any almost any consistently applied style (as long as it isn't the GNU one).Coding standards removing language features considered "dangerous" are nothing but roadblocks preventing the skilled programmer from doing his job.

  11. Paul says:

    I think it's worth considering the context of "Goto Considered Harmful". Published in 1968, if/for/while/functions were somewhat of a novelty and the article an advocacy piece. When we discuss goto today, we're not talking about the same messes of non-linear control flow orchestrated by the goto of yesterday. In that light, our quibbles are but minor points of doctrine."Goto Considered Harmful" is no less relevant today for unstructured code has new prophets and goto new and friendlier names.

  12. The Walrus says:

    Gotos have their place. A very small place. i've been writing embedded code for a couple of decades and I think I've used a goto maybe once in that time.You can almost always find a way not to use goto, which is not silly and difficult to understand. Every once in a while, you can't.The point about things like coding standards is they should encapsulate good practice. Follow them, and its harder to shoot yourself in the foot. Coding stands need an out clause:"You may break any rule in this standard provided you place extensive commetns in your code explaining why you are using a poor practice". In essence – all sins are forgiven if your explain.To say that coding standards prevent a skilled programmer is a cop out. The sort of statement made by people who insist they know better and who go their own way (and I have had to work with a few of those… and a miserable time is had by all). Coding standards make life easier by removing a whole series of needs to THINK about certain things, they make better consistency in readability which makes maintenance easier, and they help a team to work together.And provided an occasional deviation from the standard is explained in comments, then the sins are forgiven. If not explained, then the "skilled programm" should roast slowly in the fires of hell!

  13. Nigel Jones says:

    Walrus – very nicely put. I think you have summarized very nicely how to handle these sorts of situations.

  14. Max says:

    Nigel, your post triggered a series of events that eventually led me to devise a way to implement a RAII idiom, getting rid of the goto needs for error handling with cleanup. The solution I propose let you write code such as:

    bool
    f( void )
    {
    RAII_INIT;

    Foo foo;
    FILE* file;
    void* memory;

    RAII_CTOR( memory, malloc, 100 );
    RAII_CTOR( file, fopen, “zippo”, “w” );
    RAII_CTOR( &foo, Foo, 0 );

    return true;

    RAII_TRAP;
    return false;
    }

    If you mind to give a look at my post (http://www.maxpagani.org/blog.php?entry=20100319150904) I’ll be happy to hear your feedbacks. Thank you.

  15. JuKu says:

    Goto’s are not harmful (in right place), multiple destinations are. For example, I’ve coded the same problem* in various products several times; I haven’t tried to do-break approach, but I’ve done a switch, if-else if-else if… and goto solutions. The goto solution is by far the easiest to handle, when the function grows.

    *: The problem is a multiple choice scenario, and the following turns out to be easiest to maintain:

    if(this condition)
    {
    handle “this” condition;
    goto end_of_function;
    }

    if(that condition)
    {
    handle “that” condition;
    goto end_of_function;
    }

    end_of_function:
    cleanup, report situation etc.
    return;

    Now, assume there are a few ten situations to handle, each taking about a screenful of code. This 1000+ line function is very maintainable and a missed } gives an error message close to where the error is. Efficient, too.

  16. GroovyD says:

    Lots of good comments about ‘goto’s, now how about some regarding:

    (a) ? (b) : (c)

    I hear every now and then using this construct is not clear but recently i find myself using it more often for example:

    bool ledState = ledFlash ? LedFlashState() : LedNotFlashState();

    Thoughts?

    • Nigel Jones says:

      The C language is a small language and so I tend to use most of its constructs, including the ternary operator. I particularly like it when for readability reasons I need the source code to be compact. (For example if by using the ternary operator I can keep an entire function on the screen, thus making it easier to see the big picture). Having said that, there are compilers where the ternary operator is not as efficient as an if-then-else. You’ll find my thoughts on this here.

  17. GroovyD says:

    …or better yet…

    SetLedState( ledFlash ? GetLedFlashState() : GetLedNotFlashState());

  18. Jim Sawyer says:

    ” … without using ‘break’ or ‘goto’
    can rapidly lead to code
    that is a nightmare to follow

    True dat.
    However,

    ” … once one gets beyond about four or five tests of the type you are performing,
    I’d say that the code becomes impossible to follow
    unless you use either the style you have espoused
    or a goto statement.

    Not so!
    The important thing is to keep everything
    small && readable
    regardless of what constructs you use.

    I use functional decomposition,
    as in “many small bite size pieces”.

    You might not, and that’s ok.
    I guess. As long as its readable.

    ===

    typedef uint = unsigned int;
    typedef tripleX XXX_UGLYEXTERNALLY_NAMED_THING_CRIPES_BASKULEE_OVER_DUDE;

    bool aValidTripleX(tripleX toBeChecked)
    {
    if(toBeChecked==NULL) {return FALSE};
    if(!XXX_IS_ALL_GOOD) {return FALSE};
    return TRUE;
    }

    uint AddVerifiableTripleXRequestExample (uint aReadableName, uint *aReadableNameHandle)
    {
    uint status;

    if (!aValidTripleX (aReadableName)) {return ERROR_InvalidInstance};
    if (aReadableNameHandle == NULL) {return ERROR_InvalidArgument};
    if(ICouldGoOnAndOnCauseItsPrettyReadable && XXX_WHATEVER) {return ERROR_NoCanDo};

    status = XXX_SOME_STATUS;
    while (status == XXX_SOME_STATUS) do
    {
    status = AddTripleXRequest (aReadableName, aReadableNameHandle);
    };
    if(status == XXX_BAD_STATUS) {return WARNING_PartialRequest};

    return PROGESS_CompleteRequest;
    }

    ===

    But what about single exit?
    Suppose a change is needed, and now every path must II before EE except after CC?

    ===

    uint ModifiedAddVerifiableTripleXRequestExample (bool isAfter, uint aReadableName, uint *aReadableNameHandle)
    {
    uint holdEverything;

    if(!isAfter) {DickTracyCallingJoeJitsu(II);}

    holdEverything = AddVerifiableTripleXRequestExample (uint aReadableName, uint *aReadableNameHandle);

    if(isAfter) {DickTracyCallingJoeJitsu(II);}

    return holdEverything;
    }

  19. There is one top reason of using goto.
    This is a search of an element in bi-dimensional table.
    This requires 2 nested for loops.
    The table can be in fact an array of lists, anything heterogenous.
    Very often found in numerical algorithms.

    This is a top operation, often involving looking max value element in an array etc.

    As break exits only one level, you can use either return or goto.
    the former implies creating a separate function just for the scanning job.

  20. Hernan says:

    Sometime there is a difficult choice between readability vs.. many things
    I used to choose readability when I can, and I believe many things come with it 😉

    I would like to answer the original e-mail,
    Telling to take a look to a .h header I wrote for [error handling]

    http://sourceforge.net/projects/delorean/

    I hope you like, thanks!

    • Nigel Jones says:

      Hi Hernan:
      I’ve taken a quick look at what you have done. Quite frankly I need more time than I have now to digest it, so I will try and get to it this weekend and give you a more thoughtful response.

  21. […] days ago I read an article about goto heresy that triggered me to write about my personal experience with the infamous goto instruction in C. […]

Leave a Reply