I want to write a macro that spits out code based on the boolean value of its parameter. So say DEF_CONST(true)
should be expanded into const
, and DEF_CONST(false)
should be expanded into nothing.
Clearly the following doesn't work because we can't use another preprocessor inside #defines:
#define DEF_CONST(b_const) \
#if (b_const) \
const \
#endif
_Generic
is an example. You may need to check if uintmax_t
has a different underlying type than unsigned long long
.
You can simulate conditionals using macro token concatenation as follows:
#define DEF_CONST(b_const) DEF_CONST_##b_const
#define DEF_CONST_true const
#define DEF_CONST_false
Then,
/* OK */
DEF_CONST(true) int x; /* expands to const int x */
DEF_CONST(false) int y; /* expands to int y */
/* NOT OK */
bool bSomeBool = true; // technically not C :)
DEF_CONST(bSomeBool) int z; /* error: preprocessor does not know the value
of bSomeBool */
Also, allowing for passing macro parameters to DEF_CONST itself (as correctly pointed out by GMan and others):
#define DEF_CONST2(b_const) DEF_CONST_##b_const
#define DEF_CONST(b_const) DEF_CONST2(b_const)
#define DEF_CONST_true const
#define DEF_CONST_false
#define b true
#define c false
/* OK */
DEF_CONST(b) int x; /* expands to const int x */
DEF_CONST(c) int y; /* expands to int y */
DEF_CONST(true) int z; /* expands to const int z */
You may also consider the much simpler (though potentially less flexible):
#if b_const
# define DEF_CONST const
#else /*b_const*/
# define DEF_CONST
#endif /*b_const*/
Doing it as a paramterised macro is a bit odd.
Why not just do something like this:
#ifdef USE_CONST
#define MYCONST const
#else
#define MYCONST
#endif
Then you can write code like this:
MYCONST int x = 1;
MYCONST char* foo = "bar";
and if you compile with USE_CONST
defined (e.g. typically something -DUSE_CONST
in the makefile or compiler options) then it will use the consts, otherwise it won't.
Edit: Actually I see Vlad covered that option at the end of his answer, so +1 for him :)
Success story sharing
#define DEF_CONST(b_const) CONCATENATE(DEF_CONST_, b_const)
.##
' or '#
') preprocessor operators almost always really need a level of indirection to work as desired: stackoverflow.com/questions/1767683/…