Preprocessor fails due to - '#' is not followed by a macro parameter

There is no nice clean solution. But there are solutions of varying ugliness.

If you don't mind including both the id and the sequence in the macro definition, it can be solved like this:

#define CONCAT2(x,y) x##y
#define CONCAT(x,y) CONCAT2(x,y)
#define REQ_ENTRY_YES(p1, p2) { p1 , p2 }
#define REQ_ENTRY_NO(p1) 
#define IS_PAIR_HELPER(a, b, c, ...) c
#define IS_PAIR(...) IS_PAIR_HELPER(__VA_ARGS__, YES, NO)
#define REQ_ENTRY(pair) CONCAT(REQ_ENTRY_, IS_PAIR(pair))(pair)

#define ID_1 78723649, 1
#define ID_3 2347602, 3

typedef struct {
    int parm1,
        parm2;
} MyTypedef_t;

static const MyTypedef_t MyList[] =
{
    REQ_ENTRY( ID_1 )
    REQ_ENTRY( ID_2 )
    REQ_ENTRY( ID_3 )
    REQ_ENTRY( ID_4 )
    REQ_ENTRY( ID_5 )
};

Run through gcc with -std=c11 -Wall -E, and showing only the MyList definition:

static const MyTypedef_t MyList[] =
{
    { 78723649 , 1 }

    { 2347602 , 3 }


};

You can do the same thing by using any second value in the #define ID_x macros, as long as there is one; the real parameters can be added to REQ_ENTRY. But it takes some extra juggling.


It's a pity that the defined operator is available only in the context of #if and #ifelse, but not for macro expansions. As it stands, I agree with rici about the solutions of varying ugliness.

Here's a solution that requires that the defined values be surrounded by parentheses. You can then use the ID as regular value and you can also pass it to DEF, which expands to either 1 when the macro is in parentheses or 0 if not. (That's a trick I learned here.)

With the help of the DEF macro, you can create auxiliary macros that expand or ignore the given definition:

/* Auxiliary macros */

#define M_CHECK(...) M_CHECK_(__VA_ARGS__)
#define M_CHECK_(a, b, ...) b

#define M_IS_PAREN(x) M_CHECK(M_IS_PAREN_ x, 0)
#define M_IS_PAREN_(...) 1, 1

#define M_CONCAT(a, b) M_CONCAT_(a, b)
#define M_CONCAT_(a, b) a ## b

/* Conditional definition macros */

#define DEF(x) M_IS_PAREN(x)

#define DEF_IF_0(id, def)
#define DEF_IF_1(id, def) {id, def},

#define COND_DEF(x, y) M_CONCAT(DEF_IF_, DEF(x))(x, y)

/* Implementation */

#define ID_1 (27)
#define ID_3 (28)
#define ID_4 (29)

static const MyTypedef_t MyList[] = {
    COND_DEF(ID_1, 1)
    COND_DEF(ID_2, 2)
    COND_DEF(ID_3, 3)
    COND_DEF(ID_4, 4)
    COND_DEF(ID_5, 5)
};

This will produce:

static const MyTypedef_t MyList[] = {
    {(27), 1},

    {(28), 3},
    {(29), 4},

};

You can also use the DEF macro in code, which will be expanded to either 0 or 1:

printf("ID_1 is %s.\n", DEF(ID_1) ? "defined" : "undefined");

This is the closest I was able to get without introducing redundancy:

#define PREPROCESSOR_IF #if
#define PREPROCESSOR_ENDIF #endif
#define PREPROCESSOR_NEWLINE /*
*/

#define REQ_ENTRY(parm_1, parm_2)                         \
PREPROCESSOR_IF defined(parm_1)      PREPROCESSOR_NEWLINE \
    { parm_1, parm_2 },              PREPROCESSOR_NEWLINE \
PREPROCESSOR_ENDIF

typedef struct {
    int parm1,
        parm2;
} MyTypedef_t;

static const MyTypedef_t MyList[] =
{
    REQ_ENTRY( ID_1, 1 )
    REQ_ENTRY( ID_2, 2 )
    REQ_ENTRY( ID_3, 3 )
    REQ_ENTRY( ID_4, 4 )
    REQ_ENTRY( ID_5, 5 )
};

You need to run the preprocessor only once using -E and -CC and then compile the result of the first preprocessor pass, however it does not work due to (for example)

#if defined (ID_1) /*
*/ { ID_1, 1 }, /*
*/ #endif

not being recognized as distinct lines for the preprocessor, since the comments are replaced by just one space.

I was able to come up with a solution using redundancy, but it is hardly better than what you proposed (writing out the whole statement each time):

#define PREPROCESSOR_IF #if
#define PREPROCESSOR_ENDIF #endif
#define PREPROCESSOR_DEFINE #define
#define PREPROCESSOR_NEWLINE /*
*/

#define REQ_ENTRY_1(parm_1, parm_2) PREPROCESSOR_IF defined(parm_1)
#define REQ_ENTRY_2(parm_1, parm_2) { parm_1, parm_2 }, 
#define REQ_ENTRY_3(parm_1, parm_2) PREPROCESSOR_ENDIF

PREPROCESSOR_DEFINE ID_1 (27)
PREPROCESSOR_DEFINE ID_3 (28)
PREPROCESSOR_DEFINE ID_4 (29)

typedef struct {
    int parm1,
        parm2;
} MyTypedef_t;

static const MyTypedef_t MyList[] =
{
    REQ_ENTRY_1( ID_1, 1 )
    REQ_ENTRY_2( ID_1, 1 )
    REQ_ENTRY_3( ID_1, 1 )

    REQ_ENTRY_1( ID_2, 2 )
    REQ_ENTRY_2( ID_2, 2 )
    REQ_ENTRY_3( ID_2, 2 )

    REQ_ENTRY_1( ID_3, 3 )
    REQ_ENTRY_2( ID_3, 3 )
    REQ_ENTRY_3( ID_3, 3 )

    REQ_ENTRY_1( ID_4, 4 )
    REQ_ENTRY_2( ID_4, 4 )
    REQ_ENTRY_3( ID_4, 4 )

    REQ_ENTRY_1( ID_5, 5 )
    REQ_ENTRY_2( ID_5, 5 )
    REQ_ENTRY_3( ID_5, 5 )
};

This does compile as desired using the two-step compilation process described above.

Tags:

C

Macros