Jordan McBain
Jordan McBain

Reputation: 275

C macro database - Test a macro function's parameter in another macro

I am trying to create a C macro table that takes a series of C function macros and turns it into a list of one of the parameters of the C function macro if another parameter of the C function macro satisfies some condition.

For instance, define a database in FancyPantsTable.h:

#if defined (MY_FANCY_PANTS_TABLE)
FANCY_PANTS_DB( A, 123)
FANCY_PANTS_DB( B, 456)
FANCY_PANTS_DB( C, 456)
FANCY_PANTS_DB( D, 123)
#endif

Then, in FancyPants.c, import the FancyPantsTable.h everywhere you want to make a list.

#define numberSought 456

uint8 my456Array [] = {

            #define FANCY_PANTS_DB( aUint8, num ) #if  ( num == numberSought sought ) aUint8, #endif
            #define MY_FANCY_PANTS_TABLE
            #include "FancyPantsTable.h"
            #undef MY_FANCY_PANTS_TABLE
};

#define numberSought 123

uint8 my123Array [] = {

            #define FANCY_PANTS_DB( aUint8, num ) #if  ( num == numberSought sought ) aUint8, #endif
            #define MY_FANCY_PANTS_TABLE
            #include "FancyPantsTable.h"
            #undef MY_FANCY_PANTS_TABLE
};

C macro templates are pain to debug; right at the #if, I get an error that says 'expected a macro parameter name.'

Is what I am doing possible. How can I fix it?

Upvotes: 2

Views: 348

Answers (2)

jxh
jxh

Reputation: 70472

Since your fancy table header file has to be aware of all the numbers, define a default macro for each number that blanks out the arguments.

#if defined (MY_FANCY_PANTS_TABLE)

// PREAMBLE
#ifndef FANCY_PANTS_DB_ENTRY_123
#define FANCY_PANTS_DB_ENTRY_123(...) 
#endif

#ifndef FANCY_PANTS_DB_ENTRY_456
#define FANCY_PANTS_DB_ENTRY_456(...) 
#endif

#define FANCY_PANTS_DB(X, Y) \
        FANCY_PANTS_DB_ENTRY_##Y(X,)

FANCY_PANTS_DB( A, 123)
FANCY_PANTS_DB( B, 456)
FANCY_PANTS_DB( C, 456)
FANCY_PANTS_DB( D, 123)

// EPILOGUE
#undef FANCY_PANTS_DB_ENTRY_123
#undef FANCY_PANTS_DB_ENTRY_456
#undef FANCY_PANTS_DB

#endif

Then, before you include the file, you define the appropriate entry macro to emit its argument.

uint8 my456Array [] = {
            #define FANCY_PANTS_DB_ENTRY_456(...) __VA_ARGS__
            #define MY_FANCY_PANTS_TABLE
            #include "FancyPantsTable.h"
            #undef MY_FANCY_PANTS_TABLE
};

uint8 my123Array [] = {
            #define FANCY_PANTS_DB_ENTRY_123(...) __VA_ARGS__
            #define MY_FANCY_PANTS_TABLE
            #include "FancyPantsTable.h"
            #undef MY_FANCY_PANTS_TABLE
};

You can probably hide the PREAMBLE and EPILOGUE portions of the header file into separate header files that are generated from a script.

Upvotes: 0

Afshin
Afshin

Reputation: 9173

Remember, a macro cannot define another one. So lines like

#define FANCY_PANTS_DB( aUint8, num ) #if  ( num == numberSought sought ) aUint8, #endif

are invalid. Pre-processor only passes once, so you cannot use something like this.

If I'm not mistakes, you can write it like this if you like:

FancyPantsTable.h:

#if MY_FANCY_PANTS_TABLE==123
 A, 
#endif
#if MY_FANCY_PANTS_TABLE==456
 B, 
 C, 
#endif
#if MY_FANCY_PANTS_TABLE==123
 D, 
#endif

FancyPants.c:

#define MY_FANCY_PANTS_TABLE 456

uint8 my456Array [] = {
            #include "FancyPantsTable.h"
             };

#undef MY_FANCY_PANTS_TABLE
#define MY_FANCY_PANTS_TABLE 123

uint8 my123Array [] = {
            #include "FancyPantsTable.h"
            };
#undef MY_FANCY_PANTS_TABLE

Even though I'm not sure if this is what you like.

Upvotes: 2

Related Questions