So that got me thinking: essentially I wanted a set of macros that I can throw into any function to alert me when something goes wrong. Similar to the BUG_ON in the kernel, or the BUG_WARN in X. But a bit more powerful than that, because the main issue I have with BUG_WARN is that it tells me when a condition fails, but not necessarily why, or what the condition was supposed to check. Two revisions later, Rusty Russell merged my new argcheck CCAN module. It provides a set of macros for error checking that do not abort and, more importantly, also work as conditions. The simplest use-case is:
#include <ccan/argcheck/argcheck.h> void calculate(int percent) { argcheck_int_range(percent, 0, 100); // now do something }If percent is outside the [0..100] range, a message with the file, function and line number is printed. And, possibly more useful, it will also print the actual value of percent. It gets more interesting when we use symbolic names, and we use the whole things as a condition:
#define MAXIMUM 100 void something(int a) { if (!argcheck_int_lt(a, MAXIMUM)) return; // now do something } int main(void) { something(500); return 0; }If a doesn't meet the condition, the error message is:
test.c:73 something(): condition "(a < MAXIMUM)" (500 < 100) failed
So not only does it give us the actual values, it also provides the symbolic names (if there are any). Which, for debugging purposes, makes the whole thing quite useful. And we don't need to double-evaluate, we can use the macro as condition. argcheck takes care to only evaluates its arguments once, so there shouldn't be any side-effects. This also goes for disabling argcheck. If ARGCHECK_DISABLE_LOGGING is defined when including argcheck.h no messages are logged but the conditions still exist and the code runs as before. The same goes for a user-defined argcheck_log function (in case you need to override the default fprintf(stderr)).
I've added quite a few macros for various use-cases, including:
- argcheck_flag_set(a, flag) - false if the flag isn't set, but also checks that the flag is not 0
- argcheck_str_not_zero_len(str) - false if the string is NULL or the empty string
- argcheck_str_max_len(str, len) - false if the string is NULL, or longer than len. Works great to warn about truncated string copies.
- argcheck_ptr_null(ptr) - false if the pointer is not NULL. Works great to spot uninitialized variables.
Any comments or feedback let me know, I'm eager to improve this to make it even more useful (it already saved my hide a few times)
No comments:
Post a Comment
Comments are moderated thanks to spammers