First of all, mysterious macros such as your CHECKERROR
which hide away flow control are widely considered very bad practice. Don't do that - creating secret macro languages that no other C programmer understands is a much more serious quality concern than code repetition. Code repetition isn't good but it shouldn't be solved by creating a much worse problem. Assume that the reader knows C well, but don't assume that they know or want to know your secret macro language local to this project.
In idiomatic C there are two acceptable ways to write this code. Either with explicit return
or with the "on error goto" pattern à la BASIC. I would generally recommend the return
version since it saves you from having that old tiresome "goto
considered harmful" debate yet again. But goto to a clean-up at the end of the function is acceptable too, as long as you only jump downwards.
(Your do-while(0)
with break
is just a goto
in disguise. It isn't better or worse.)
The single point of return
from functions is also debated, especially in the context of MISRA-C (see this). Multiple returns from a function is however fine as long as it doesn't make the code harder to read. In practice this means that you should avoid return
(or goto
) from inside deeply nested loops or statements. Generally keep the "cyclomatic complexity" (the number of possible execution paths in a function) as low as possible.
In case you need to free up resources, I personally prefer return
over goto
. For return
you need to make a wrapper function, which also serves the purpose of separating resource allocation from the algorithm. I would have rewritten your code like this:
typedef enum // use an actual enum not sloppy int
{
OK, // keeping code 0 for no error is the most common practice
ERR_THIS,
ERR_THAT
} err_t;
static err_t the_actual_algorithm (handle_t res1, handle_t res2) // likely inlined
{
err_t errorcode;
errorcode = action1(res1, res2);
if(errorcode != OK) { return errorcode; }
errorcode = action2(res1, res2);
if(errorcode != OK) { return errorcode; }
return OK;
}
err_t somefunction (void) // note void, not empty parenthesis which is obsolete style
{
handle_t res1, res2;
err_t errorcode;
res1 = getResource();
res2 = getResource();
errorcode = the_actual_algorithm(res1, res2);
freeResource(res1);
freeResource(res2);
return errorcode;
}