What is considered best practice for aborting on errors in C?
In our code base we currently have a pattern using
#define CHECKERROR(code) if(code) { return code; }
but this leads to resources not being closed in code of the form
/* not actual code due to non-disclosure restrictions */
int somefunction() {
handle_t res1, res2;
int errorcode;
res1 = getResource();
res2 = getResource();
errorcode = action1(res1, res2);
CHECK(errorcode);
errorcode = action2(res1, res2);
CHECK(errorcode);
freeResource(res1);
freeResource(res2);
return errorcode;
}
I came across the pattern
/* initialize resources */
do {
/* ... */
errorcode = action();
if(errorcode) break;
/* ... */
} while(0);
/* cleanup resources */
return errorcode;
before in articles, but couldn't find any source discussing it now.
What is a good practice, that would be considered idiomatic to C? Does the do { } while(0); pattern qualify? Is there an idiomatic way to make it more clear, that it is not intended to be a loop, but a block with non-local exit?
Really, nothing. There is no best-practice. Best is to tailor a specific solution to the specific case you are handling. For sure - concentrate on writing readable code.
Let's mention some documents. MISRA 2008 has the following. The rule is strict - single exit point. So you have to assign variables and jump to a single
returnstatementError handling is the only place where using
gotois actually encouraged. Linux Kernel Coding style presents and encourages usinggototo "keep all exit points close". The style is not enforced - not all kernel functions use this. See Linux kernel coding style # Centralized exiting of functions.The kernel recommendation of
gotowas adopted by SEI-C: MEM12-C. Consider using a goto chain when leaving a function on error when using and releasing resources.Sure, why not. If you do not allocate any more resources inside the
do { .. here .. }while(0)block, you might as well write a separate function and then callreturnfrom it.There are also expansions on the idea. Even implementations of exceptions in C using
longjmp. I know of ThrowTheSwitch/CException.Overall, error handling in C is not easy. Handling errors from multiple libraries becomes extremely hard and is an art of its own. See MBed OS error-handling, mbed_error.h, even a site that explains MBed OS error codes.
Strongly prefer single return point from your functions - as you found out, using your
CHECK(errorcode);will leak resources. Multiplereturnplaces are confusing. Consider usinggotos: