Using #ifdef
inside of #define
is not possible. But there are still ways you can detect wether or not a macro has been defined within a macro definition.
1. Solution
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c
#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value
#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)
PRINT_IF_DEBUGGING(foo)
will expand to:
- if
DEBUG
is defined: debugPrint(foo)
- if
DEBUG
is not defined: print(foo)
Example:
PRINT_IF_DEBUGGING("test1");
#define DEBUG
PRINT_IF_DEBUGGING("test2");
#undef DEBUG
PRINT_IF_DEBUGGING("test3");
would result in:
print("test1");
debugPrint("test2");
print("test3");
2. How IS_DEBUG_DEFINED()
works
The fundamental trick behind this is to use concatenation - if the macro was defined it will be expanded, otherwise the token will be left unmodified by the preprocessor:
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
// DEBUG NOT DEFINED:
CAT(CHECK_,DEBUG) // will expand to CHECK_DEBUG
// DEBUG DEFINED:
#define DEBUG 1234
CAT(CHECK_,DEBUG) // will expand to CHECK_1234
- The first
CAT
will expand to CHECK_DEBUG
, because DEBUG
was not defined.
- The second
CAT
however will expand to CHECK_1234
, because DEBUG
was defined and expanded to 1234
before the concatenation with CHECK_
.
By defining a macro named CHECK_DEBUG
we can change the result if the macro was not defined, e.g.:
godbolt
#define TEST CAT(CHECK_,DEBUG), 0, 1
#define CHECK_DEBUG ~,~
- If
DEBUG
is not defined the result will be ~, ~, 0, 1
(4 comma-separated tokens)
- If
DEBUG
is defined the result will be CHECK_, 0, 1
(3 comma-separated tokens)
Notice how we got 4 tokens in the first case, but only 3 tokens in the second.
Now all we need to do is take the 3rd token from that sequence (which will be 0
if DEBUG
is not defined and 1
otherwise), for example with a simple macro that always returns the 3rd argument:
#define CHECK(a, b, c, ...) c
Putting it all together, this is what a full IS_DEBUG_DEFINED()
could look like:
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c
IS_DEBUG_DEFINED()
will expand to 0
if DEBUG
is not defined, and 1
if it is, e.g.:
IS_DEBUG_DEFINED() // -> 0
#define DEBUG
IS_DEBUG_DEFINED() // -> 1
#undef DEBUG
IS_DEBUG_DEFINED() // -> 0
With IS_DEBUG_DEFINED()
you can then use a standard preprocessor IIF
to change the behaviour of your macro depending on wether DEBUG
is defined or not.
Example: godbolt
#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value
#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)
PRINT_IF_DEBUGGING("test"); // -> print("test");
#define DEBUG
PRINT_IF_DEBUGGING("test"); // -> debugPrint("test");
#undef DEBUG
PRINT_IF_DEBUGGING("test"); // -> print("test");
3. Caveats
One small caveat with this is that if DEBUG
is defined it must expand to a valid preprocessing token (so it must only contain letters, digits and underscores) - otherwise the concatenation will result in an error.
So this would not work:
#define DEBUG ()
#define DEBUG +