I tend to follow a standard idiom when writing C functions
which allocate resources. At the top, I define a variable
for each resource, and initialize it to a sentinel value
meaning that it’s not yet active, and another for the
function’s return value. At the bottom, I define a label
end
, where I release all of the resources which still seem
live, and return the right result. If something goes wrong
partway through, I set the return value to indicate the
problem, and goto end
. Easy.
But it means that the code to release a thing isn’t near where it’s defined or allocated.
I had a brainwave the other day, and wrote a macro.
#define FINALLY(body) \
__extension__ __inline__ TMP(finally_fn) \
(const int __attribute__((unused)) *hunoz) { body } \
int __attribute__((unused, cleanup(TMP(finally_fn)))) \
TMP(finally_var)
The TMP
macro decorates an identifier so that it’s (more or
less) private to the macro invocation. Now I can say
something like
void *p = 0; FINALLY({ free(p); });
and I can use return
as usual for an early exit. Yay.
(Apparently I’m not the only person who’s thought of this.)
This macro has two problems.
Firstly, it uses nested functions, so it only works with GCC. Clang doesn’t support these, presumably because there’s no good way to implement a pointer to a nested function.
Secondly, the syntax is ugly, involving parentheses and a final semicolon.
I can’t figure out a way to solve both problems at the same time.