'Test if a C macro's value is empty
I need to write some code to verify that a macro is defined but empty (not having any values). The test does not need to be in compile time.
I am attempting to write:
#if (funcprototype == "")
MY_WARN("funcprototype is empty");
#endif
the code does not compile, as funcprototype expands to empty.
Solution 1:[1]
If a run-time check is okay, then you can test the length of the stringized replacement:
#define REAL_STRINGIZE(x) #x
#define STRINGIZE(x) REAL_STRINGIZE(x)
if (STRINGIZE(funcprototype)[0] == '\0') {
// funcprototype expanded to an empty replacement list
}
else {
// funcprototype expanded to a non-empty replacement list
}
I don't think there is a general-case "is this macro replaced by an empty sequence of tokens" compile-time check. That is a similar problem to "is it possible to compare two sequences of tokens for equality," which is impossible to do at compile-time.
Solution 2:[2]
C++20 __VA_OPT__ makes this easier:
#define EMPTY(...) (true __VA_OPT__(&& false))
Then:
if (EMPTY(MY_MACRO))
Solution 3:[3]
With VS2013 the following works for me at pre-compile-time:
#define EXPAND(x) x
#define ARGS_dummy(...) dummy,##__VA_ARGS__
#define SELECT_from5(_1,_2,_3,_4,_5,num,...) num
#define IS_EMPTY_impl(...) EXPAND(SELECT_from5(__VA_ARGS__,0,0,0,0,1))
#define IS_EMPTY(...) EXPAND(IS_EMPTY_impl(ARGS_dummy(__VA_ARGS__)))
IS_EMPTY expands to 1 if there is no argument or the 1st argument expands to nothing, otherwise to 0.
Additional arguments are ignored.
#define x2 X
#define x1
#undef x0
IS_EMPTY(); // () -> 1
IS_EMPTY( ); // ( ) -> 1
IS_EMPTY(,); // (,) -> 1
IS_EMPTY(aaa,); // (aaa, ) -> 0
IS_EMPTY(,,); // (,,) -> -> 1
IS_EMPTY(x2); // (x2) -> (X) -> 0
IS_EMPTY(x1); // (x1) -> () -> 1
IS_EMPTY(x0); // (x0) -> 0
Now you could generate a bit mask depending on empty/nonempty parameters:
#define check_5e(a,b,c,d,e) a ## b ## c## d ## e
#define check_5d(a,b,c,d,e) check_5e(a,b,c,d,e)
#define check_5c(e,a,b,c,d) check_5d(a,b,c,d,IS_EMPTY(e))
#define check_5b(d,e,a,b,c) check_5c(e,a,b,c,IS_EMPTY(d))
#define check_5a(c,d,e,a,b) check_5b(d,e,a,b,IS_EMPTY(c))
#define check_5(b,c,d,e,a) check_5a(c,d,e,a,IS_EMPTY(b))
#define CHECK_FIVE_ARGS(a,b,c,d,e) check_5(b,c,d,e,IS_EMPTY(a))
CHECK_FIVE_ARGS(aa, , x1, x2, x0); // -> (aa,,,X,x0) -> 01100
or you can choose sub macro depending on given arguments ... (note that VERSION_BUILD is defined but empty!)
#define VERSION_Major 3
#define VERSION_Minor 22
#define VERSION_Patch 111
#define VERSION_Build
#define VERSION_Label debug
#define MAKE_VERSION_11(a,b,c,d,e) a##.##b##.##c
#define MAKE_VERSION_10(a,b,c,d,e) a##.##b##.##c##--##e
#define MAKE_VERSION_01(a,b,c,d,e) a##.##b##.##c##-##d
#define MAKE_VERSION_00(a,b,c,d,e) a##.##b##.##c##-##d##--##e
#define MAKE_VERSION_impl2(_de) MAKE_VERSION_ ## _de
#define MAKE_VERSION_impl(_de) EXPAND(MAKE_VERSION_impl2(_de))
#define MAKE_VERSION(a,b,c,d,e) \
MAKE_VERSION_impl(IS_EMPTY(d)IS_EMPTY(e))(a,b,c,d,e)
// check 4th and 5th arg -> "MAKE_VERSION_10"
MAKE_VERSION_impl(IS_EMPTY(VERSION_Build)IS_EMPTY(VERSION_Label));
// -> 3.22.111--debug
MAKE_VERSION(VERSION_Major, VERSION_Minor, VERSION_Patch, VERSION_Build, VERSION_Label);
MAKE_VERSION(2, 3, 4, 5678, ); // -> 2.3.4-5678
MAKE_VERSION(2, 3, 4, 5678, beta); // -> 2.3.4-5678--beta
MAKE_VERSION(2, 3, 4,,); // -> 2.3.4
MAKE_VERSION(2, 3, 4, ,beta); // -> 2.3.4--beta
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | James McNellis |
| Solution 2 | HolyBlackCat |
| Solution 3 |
