This question concerns "C preprocessor metaprogramming", i.e. stuff such as this, this, this, this, etc.
I'm writing a non-trivial C preprocessor metaprogram, which in particular needs to "call" macros recursively (using the standard DEFER
/EVAL
tricks), and these macros will need to declare variables:
#define F(x, y) \
do { \
int var; \
\
/* ... */ \
\
DEFER(F)()(var, y) \
} while (0)
However, this creates a variable var
shadowing those on the outer scopes, which is a problem if I need to pass var
itself as one of the parameters to F()
(i.e. the recursive "call" needed to access var in the preceding scope). The solution I found was to concatenate a symbol such as _
at each level of recursion:
#define CAT(x, y) CAT_IMPL(x, y)
#define CAT_IMPL(x, y) x##y
#define F(x, y, l) \
do { \
int CAT(var, l); \
\
/* Code that uses CAT(var, l) extensively */ \
\
DEFER(F)()(CAT(var, l), y, CAT(l, _)); \
} while (0)
So, assuming the initial "call" to F()
is of the form F(x, y, _)
, then var_
will be declared; in the first recursion level, var__
will be declared; in the second, var___
, and so on.
This is working, but the code is littered with occurrences of CAT(var, l)
making it even more unreadable than such code usually already is. I'm looking for the most compact syntax possible to make the code a little less unreadable, i.e. something like V(var)
, without needing to spell out the , l
part explicitly.
However, I'm having trouble writing a macro to make this work (assuming it is even possible).
Here is an MRE, which isn't even a valid C program, but will demonstrate what I'm looking for if run through the preprocessor alone, i.e. using gcc -E
:
#define CAT(x, y) CAT_IMPL(x, y)
#define CAT_IMPL(x, y) x##y
#define F1(x, l) CAT(x, l)
#define CATL(x) CAT(x, l)
#define F2(x, l) CATL(x)
F1(var, _)
F2(var, _)
The result of preprocessing this (removing garbage at the beginning) is:
var_
varl
What I'd like is a version of CATL()
with a single macro parameter (i.e. without explicitly passing l
as a parameter) but that still "captured" l
, so as to get the following output instead:
var_
var_
That is not possible, there is no "global stack" in preprocessor, and there is no state, the only stack is in the arguments. I do not see a way of capturing the current depth of the callstack except for passing a parameter.
Consider using a different programming language for C code generation - M4, Jinja2, PHP, Python, shell.