Handling errors in C

Christopher Bazley, January 2015

Most programmers who have written a significant amount of code in a language without a built-in exception mechanism will have written code like this:

Exception e;
e = try_foo(baz);
if (e) goto exit;
e = try_bar(foo);
if (e) goto exit;
e = try_baz(bar);
if (e) goto exit;
flibble_wotsit();
exit:

However, the code above could equally well have been written as follows:

Exception e;
e = try_foo(baz);
if (!e) e = try_bar(foo);
if (!e) e = try_baz(bar);
if (!e) flibble_wotsit();

Only the stupidest compiler will fail to spot that if one !e expression evaluates as false then so do all subsequent instances of the same expression; in any case the efficiency of an exception-handling path is rarely performance-critical. The complexity of the second form is not greater, nor does it cause the so-called 'arrow indentation antipattern'.

Why, then, is the first form so prevalent, given that programming without 'goto' statements was the original goal of structured programming dogmatists? I can only explain it in terms of one dogma superseding another: the dogma of "Use goto to handle exceptional circumstances" has superseded the dogma of "never use goto". I cannot see this as a good thing.