I much preferred (and still greatly prefer in industry) the pattern of exiting the function as soon as possible.
Returning and throwing quickly and strict.
int foo(thing_t \*work) {
int ret = E_SUCCESS;
if(work->thing == BAD_THING) {
ret = E_BAD;
goto exit;
}
do_some(work);
if(work->thing2 == OTHER_BAD_THING) {
LOG("whoopsies");
ret = E_OTHER;
goto exit;
}
ret = do_more(work);
if (!ret) {
LOG("lazy");
goto exit;
}
ret = last_bit_of(work);
exit:
return ret;
}