0

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?

Christian
  • 149
  • 1
  • 8
  • 1
    What _actual_ problem are you trying to solve. Read [this](http://xyproblem.info/) – Jabberwocky Feb 26 '20 at 10:09
  • See https://stackoverflow.com/questions/5586429/ifdef-inside-define – manuell Feb 26 '20 at 10:14
  • All solutions for this problem are just depending on a single compiler switch. But I want to have a separate compiler switch for each macro call. Finally DECLARE will define a variable and a function, which will be called by another macro for code instrumentation. – Christian Feb 26 '20 at 10:30
  • 1
    @Christian Please [edit] your question to add information instead of writing comments. I suggest to show an example how you want to look the source code after macro expansion with different compiler switch settings. – Bodo Feb 26 '20 at 10:57
  • I don't think you should call it a compiler "switch" but rather a "command line define". Many compile have something like `-dMY_DEFINE` which defines the symbol `MY_DEFINE` to the compilation unit. – Paul Ogilvie Feb 26 '20 at 11:20
  • Your problem here is not making a `#define` conditional upon `ENABLE_var1` or `ENABLE_var2`—[that is usually accomplished by making the macro definition contingent upon tests in `#if` directives](https://stackoverflow.com/questions/5586429/ifdef-inside-define)—but the fact that you want to make it contingent upon whether its argument is `var1` or `var2`, since you show `DECLARE(var1)` and `DECLARE(var2)` doing different things. To solve that, you need to explain how the arguments are to be distinguished. If they are not literally `var1` and `var2`, what makes them different? – Eric Postpischil Feb 26 '20 at 12:46
  • DECALRE will always get the variable name. And the corresponding "compiler switch" (for me -D is exactly that) will always consist of the same prefix followed by the variable name. DECLARE shall be part of a library. The implementer will decide, how many variables he wants to declare and set the compiler switch specifically. – Christian Feb 26 '20 at 14:35
  • @Christian it does not make any sense and the code will be very difficult to read. #if is the correct way. – 0___________ Feb 26 '20 at 14:36
  • 1
    @Christan can you give us a better example. I do not understand the goal of this. If you pass two flags you would get both declared, since you have no #ifdef – Gerhard Stein Feb 26 '20 at 14:44

1 Answers1

1

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • What is the likely better way? – Christian Feb 27 '20 at 17:58
  • @Christian: To start with, leave the code the way it is, using `#ifdef ENABLE_var1` / `int var1;` / `#endif` as described at the start of your question. The information in your question does not give any motivation for doing anything different, so why complicate things? – Eric Postpischil Feb 27 '20 at 18:00
  • Finally this shall be part of a debugging lib to add code instrumentation. So anyboday shall simply add some macro and may afterwards enable specific instrumentation by -D option. For this I need a variable depending on compiler switch - so exactly what I requested :-) – Christian Feb 29 '20 at 11:14
  • @Christian Without knowing what exactly your debugging lib is expected to do, it is difficult to decide what is a "good" or "better" solution. It might help to explain in your question what you want to achieve from the user's point of view. (Defining a variable or not is the point of view of the implementation.) What kind of "specific instrumentation" shall be enabled by defining preprocessor macros? – Bodo Mar 02 '20 at 12:10
  • @Christian: Anybody adding “specific instrumentation” can simply conditionalize it with `#if defined ENABLE_varx` … `#endif`. There is no reason to make some fancy `DECLARE` macro. – Eric Postpischil Mar 02 '20 at 12:15