1
votes

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.

1
Maybe you should not abuse macros this way, and consider generating some C code (from some script or program), perhaps in some included header....Basile Starynkevitch
But even if you could do what you want (and I don't understand your exact wish) with macros, you could have very unreadable code. Sometimes, coding a simple awk script generating some simple header containing some #define-s is much simpler.Basile Starynkevitch
Did you consider some form of X macros? Also please edit your question by giving the desired preprocessor input and output; I don't exactly understand your wish (and your motivations)Basile Starynkevitch

1 Answers

2
votes

I would like this code:

 #define NAME(SOME_MACRO_CONST)  (123)
 #define NAME(SOME_MACRO_CONST2) (124)

To expand to:

 #define 3SOME_MACRO_CONST  (123)
 #define 3SOME_MACRO_CONST2 (124)

(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:

      /// new desired expansion
      #define THREE_SOME_MACRO_CONST  (123)
      #define THREE_SOME_MACRO_CONST2 (124)
    
  • 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 anonymous enum like

 enum {
   THREE_SOME_MACRO_CONST= 123,
   THREE_SOME_MACRO_CONST2= 124,
 };

and 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 or awk ...), 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!