On Thursday, 4 October 2018 at 06:43:02 UTC, Gopan wrote:
Any advices?
In C, I will layout my functions like that (that's especially
good for initializer functions):
int init(struct my_handle *handle, ...)
{
if (handle == NULL)
return -EINVAL; // direct return for parameter safety check
if (other_arg > MY_MIN || other_arg > MY_MAX)
return -EINVAL; // same here
handle->data == calloc(1, SIZE);
if (handle->data == NULL)
return -ENOMEM; // return when memory allocation fails,
// I assume my program won't recover anyway
// create some system resource
handle->fd = fopen("bla.txt", "w");
if (handle->fd == NULL)
goto error; // goto error, because I have some cleanup to do
// I will use goto's from now on every time I
have
// some action that return an error
...
return 0; // Success
error:
close(handle->fd); // maybe check first fd is valid...
free(handle->data);
return -EFAIL;
}
My basic rules are:
1- Argument safety check before anything else, return
straightaway.
2- If memory allocation fails, return (or assert), no cleanup,
unless you expect to recover from it, so that is a resource
allocation like described in the next point.
3- If some resource allocation fails, escape using a goto
statement to final label. I call it "error" for simple cases,
else "error_closepipe", "error_epoll" etc, depending on the
resource I'm cleaning up.
4- error handling is after a successful "return 0;" which
finalizes a nominal execution flow.
5- Maybe use some "int ret" to carry some error code at the end,
and maybe log it, for easier debugging.
6- Don't use a return statement in a loop. Break from it: there
could be some cleanup to do after the loop.
As a side-note, one instruction is one operation, I don't like:
if ((ret = handle->doSomeStuff(args)) < 0)
goto error;
I prefer:
ret = handle->doSomestuff(args);
if (ret < 0)
goto error;
It's especially annoying to read (and thus maintain) if some
other conditions are tested in the if-statement.