Christian
Christian

Reputation: 179

C macro expansion including compiler switches

My current implementation defines a couple of variables depending on corresponding compiler switches:

#ifdef ENABLE_var1
int var1;
#endif
#ifdef ENABLE_var2
int var2;
#endif

The compiler switches will be set by -D option during make. The names will always consist of the same prefix and the variable name. Since it is always the same strategy, my idea is to replace this using a macro like:

DECLARE(var1)
DECLARE(var2)

Calling make -DENABLE_var1 should result in:

int var1;

Calling make -DENABLE_var1 -DENABLE_var2 should result in:

int var1;
int var2;

Since it is not possible to use #ifdef within a macro, is there a trick to achieve this?

Upvotes: 0

Views: 526

Answers (1)

Eric Postpischil
Eric Postpischil

Reputation: 223389

As long as the variable names to be defined, potentially, are known, then this can be accomplished:

//  Define a DEFINE_x macro for each x that might be enabled.
#if defined ENABLE_var1
    #define DEFINE_var1 int var1;
#else
    #define DEFINE_var1
#endif

#if defined ENABLE_var2
    #define DEFINE_var2 int var2;
#else
    #define DEFINE_var2
#endif

//  Define DECLARE(x) to expand to the corresponding DEFINE_x macro.
#define DECLARE(x)  DEFINE_##x

//  List potential definitions.
DECLARE(var1)
DECLARE(var2)

If the names are not known, then this kludge works:

#define Comma()                 ,
#define Argument3c(a, b, c,...) c
#define Argument3b(a, b,...)    Argument3c(a, b, __VA_ARGS__)
#define Argument3a(a,...)       Argument3b(a, __VA_ARGS__)
#define Nullify1
#define NullifyHelper(x)        Nullify##x
#define Nullify(x)              NullifyHelper(x)
#define DECLARE(x)              Argument3a(Comma Nullify(ENABLE_##x) (), int x;,,)

DECLARE(var1)
DECLARE(var2)

Understanding this requires following the preprocessing in great detail, but I will provide a few notes:

  • For -Dname, GCC defines name to be replaced by 1. The Nullify macro, with its helpers, causes ENABLE_x to be replaced by an empty sequence if ENABLE_x is defined to be 1 and by a non-empty sequence otherwise.
  • Then, if an empty sequence has resulted, we have Comma (), which expands to a comma. If it is not an empty sequence, we have Comma something (), which does not allow the function-like macro to be expanded, so some sequence not including a comma results.
  • Through the remaining macro expansions, this comma or lack thereof determines which argument is where in the argument list, allowing us to pick out either the desired definition or an empty sequence.

I advise against using this in production code. There is likely a better way to accomplish your configuration goal.

Upvotes: 1

Related Questions