I’ve been doing a lot of programming in C recently. Part of what comes with that is a lot of manual memory management. GCC and Clang have something called the cleanup attribute (among many other cool attributes that can be found here) that can be applied to variables. When a variable exits scope, a function will be implicitly called that was registered at variable declaration. That way you never have to explicitly deallocate or clean up anything later on. This is very much like how destructors work in C++. Here is an example from the otter codebase.
OTTER_CLEANUP(otter_target_free_p)
otter_target *otter_array_tests = otter_target_create(
"otter_array_tests.so", allocator, filesystem, logger,
"otter_array_tests.c", "otter_array.h", "otter_test.h", NULL);I’ve made a couple usability macros that will help if I ever need portability between compilers that express cleanup attributes differently than GCC and Clang. Right now, it is just:
#define OTTER_CLEANUP(func) __attribute__((cleanup(func)))The only annoying thing about the cleanup attribute is that it wants a function signature that accepts a pointer to the variable type being freed. So, in our example of cleaning up a variable of type otter_target*, you need to provide a void function with one argument accepting a otter_target**. This… is not how I like defining my free functions. I generally have functions that look like this in order to free a specific struct type:
void otter_target_free(otter_target *target);So we need another function that can just forward to otter_target_free. Luckily, it’s an easy macro to write so that you don’t have to manually create such a boring function. The systemd codebase has a macro that I was able to use for this and can be found here. Here is my version of it:
#define OTTER_DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##_p(type *p) { \
if (*p) { \
func(*p); \
} \
} \
struct otter_useless_struct_to_allow_trailing_semicolonSo, the previous declaration of otter_target_free can now become:
void otter_target_free(otter_target *target);
OTTER_DEFINE_TRIVIAL_CLEANUP_FUNC(otter_target*, otter_target_free);
Leave a Reply