int init_abc()
{
if (!init_a())
goto err_a;
if (!init_b())
goto err_b;
if (!init_c())
goto err_c;
return 1;
err_c:
cleanup_b();
err_b:
cleanup_a();
err_a:
return 0;
}
seems to be the cleanest way to do what it does in C. For what it's worth, it is the way a lot of error handling is done in the Linux kernel. char *foo = 0, *bar = 0;
if((foo = malloc(X)) == NULL || (bar = malloc(Y)) == NULL)
goto cleanup;
make_me_millions(foo, bar);
cleanup:
free(bar);
free(foo);
In this case, and many cases like it, there's no need to have two jump targets, because one is good enough. You'll have to declare the variables early on anyway to avoid warnings/errors from definitions that cross jump labels.So there's probably nothing wrong with multiple jump targets but that might not be needed with well-behaving cleanup functions.
You really need to check the specification on each function. free is defined that free(NULL) is no-op, but there are other things where that is not the case. Also, that code is not portable since NULL does not have to be 0.
I was always taught that (void *)0 is a valid definition of NULL, but that 0 was not necessarily.
Sure, but I need to do that anyway and constantly, since I use far too many API's to memorize. It's also convenient to make cleanup(NULL) a no-op for the API's you create.
NULL is zero. Even if the standard would allow it to be something else, it's not relevant with the compilers and platforms I use. There's no point in being a language lawyer just to achieve "portability" to some imaginary platform where a byte is 7 bits and NULL == 0xdeadbeef. Make a list of compilers and platforms you support and forget the rest if you want to get stuff done.
int init_abc()
{
if(!init_a())
return 0;
if(!init_b())
cleanup_a();
return 0;
if(!init_c())
cleanup_a();
cleanup_b();
return 0;
return 1;
}
The examples did not have any resources to clean up, and that is what makes error handling in C painful. In the absence of any cleanup routines, this will do:
Of course, once you add resources to clean up or error codes that are meaningful (not just success/fail) error handling gets more painful.You should not try to perfect something as mundane as error handling. Just write the damn code and get over it.