Background
I've utilized a set of preprocessor macros from another question that allows me to prefix symbol names (enums, function names, struct names, etc) in my source, i.e.:
#include <stdio.h>
#define VARIABLE 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun, VARIABLE)
void NAME(func)(int i);
int main(void)
{
NAME(func)(123);
return 0;
}
void NAME(func)(int i)
{
printf("i is %d in %s.\n", i, __func__);
}
Problem
This works as expected, with the following output: i is 123 in func_3.
Edit
I would like this code:
#define NAME(SOME_MACRO_CONST) (123)
#define NAME(SOME_MACRO_CONST2) (123)
To expand to:
#define 3SOME_MACRO_CONST (123)
#define 3SOME_MACRO_CONST2 (123)
I realize the macro shouldn't start with a digit. In the final code I'll be using names like LIB_A_
and LIB_B_
as prefixes.
/Edit
However, if I attempt to do the same with macros as the arguments to my NAME
variadic macro, it fails like so:
Re-using NAME
macro:
Code
#define NAME(MY_CONST) (3)
Output
test.c:7:0: warning: "NAME" redefined
#define NAME(MY_CONST) 3
Manually pasting prefix:
Code:
#define VARIABLE ## MY_CONST (3)
Output:
test.c:8:18: error: '##' cannot appear at either end of a macro expansion
#define VARIABLE ## MY_CONST (3)
Question
How can I create simple macro definitions (name + value) that has a common prefix for all the macros? The goal is to be able to make multiple copies of the source file and compile them with different flags so all versions can be linked together into the same final binary without symbol/macro name collisions (the macros will later be moved into header files). The final file will be too big to write in something like M4 or a template language. Ideally, the solution would involve being able to use a single macro-function/variadic-macro for all use cases, but I'm OK with one macro for symbol prefixing, and another for macro-name prefixing.
(I corrected the second number to 124 to make it different from the first one, for readability purposes)
This is impossible with the C preprocessor
for several reasons:
3SOME_MACRO_CONST
is not a valid identifier (both for the preprocessor, and for the C compiler itself) since it does not start with a letter or an underscore. So let's assume you want your code to be expanded to:this is still impossible, because the preprocessor works before anything else and cannot generate any preprocessor directive (e.g.
#define
).A workaround, if you only want to
#define
some numbers (computable at compile-time !!!) might be to expand to some anonymousenum
likeand you know how to do that in the details. Read also about X-macros.
However, even if you can change your requirement to something that is possible, it might be not recommendable, because your code becomes very unreadable (IMHO). You could sometimes consider writing some simple script (e.g. in
sed
orawk
...), or use some other preprocessor like GPP, to generate a C file from something else.Notice that most serious build automation tools (like GNU make or ninja) -or even IDEs (they can be configured to) permit quite easily (by adding extra targets, recipes, commands, etc...) to generate some C (or C++) code from some other file, and that meta-programming practice has been routinely used since decades (e.g. bison, flex, autoconf, rpcgen, Qt
moc
, SWIG ...) so I am surprised you cannot do so. Generating a header file containing many#define
-s is so common a practice that I am surprised you are forbidden to do so. Perhaps you just need to discuss with your manager or colleagues. Maybe you need to look for some more interesting job.Personally, I am very fond of such meta-programming approaches (I did my PhD on these in 1990, and I would discuss them at every job interview; a job where metaprogramming is forbidden is not for me. Look for example at my past GCC MELT project, and my future project also will have metaprogramming). Another way of promoting that approach is to defend domain specific languages (and the ability to make your DSL inside some large software project; for example the GCC compiler has about a dozen of such DSLs inside it....). Then, your DSL can (naturally) be compiled to C which is a common practice. On modern operating systems that generated C code could be compiled at runtime and dynamically loaded as a (generated) plugin (using dlopen on POSIX...)
Sometimes, you can trick the compiler. For a project compiled by GCC, you could consider writing your GCC plugin..... (that is a lot more work than adding a command generating C code; your plugin could provide extra magic pragmas or builtins or attributes used by some other macros).
You could also configure the spec file of your
gcc
to handle specifically some C files. Beware, that could affect every future compilation!