I have a C macro library that injects error handling in an unobtrusive way, by defining _(...). I want to extend the library with a function (a macro actually) that wraps some additional complexity but can still be used with the error handling injection macro... but this seems not to work as I hit a problem with nested/recursive macro expansion.
I've worked around this by writing a "compromise" macro to force the extra level of macro expansion that I need, but it is less than perfect because it deviates from the usual syntax for injecting error handling (refer to last line in the following example code).
Example C code:
#define _(...) (__VA_ARGS__); check_and_handle_errno()
#define DO(x, ...) (x ? do_impl(static_arg, __VA_ARGS__) : NULL)
#define DO_(x, ...) _(x ? do_impl(static_arg, __VA_ARGS__) : NULL)
type * name = do_impl(static_arg, arg2); // no error handling
type * name = do_impl _(static_arg, arg2); // with error handling
// a bit more complex
type * name = (arg1 ? do_impl(static_arg, arg2) : NULL); // no error handling
type * name = _(arg1 ? do_impl(static_arg, arg2) : NULL); // with error handling
// complexity wrapped by macro
type * name = DO(arg1, arg2); // no error handling
type * name = DO _(arg1, arg2); // with error handling, but doesn't fully expand
type * name = DO_(arg1, arg2); // compromise, but I really want the syntax above
When saved to a file (test.h) and run through the preprocessor via gcc -E test.h
, the example gets converted into the following:
type * name = do_impl(static_arg, arg2);
type * name = do_impl (static_arg, arg2); check_and_handle_errno();
type * name = (arg1 ? do_impl(static_arg, arg2) : NULL);
type * name = (arg1 ? do_impl(static_arg, arg2) : NULL); check_and_handle_errno();
type * name = (arg1 ? do_impl(static_arg, arg2) : NULL);
type * name = DO (arg1, arg2); check_and_handle_errno();
type * name = (arg1 ? do_impl(static_arg, arg2) : NULL); check_and_handle_errno();
Does anybody know how to achieve the syntax in the 2nd to last line in the example code (and have it expand to the last line in the example)?
Thanks!
I'm not sure if your desired syntax is possible, it doesn't seem to be - but logically, what you're trying to accomplish is equivalent to:
type * name = _(DO(arg1, arg2));
that is, first execute arg2
if arg1
is true, and then check the error.
This works without a third DO_
macro and isn't far off from what you seem to want.