I have a macro that looks like this:
M(id,...)
I would like it to expand to nothing if id == 0
and something else otherwise.
Is this possible? If so, how?
My first instinct was to try something like this:
#define M(id,...) M##id(__VA_ARGS__)
#define M0(...)
#define M_NOT_0(...) some_code(__VA_ARGS__)
But the last line here is obviously not valid, and I can't figure out a way to make this pattern work.
Notes:
id
is an integer between 0 and 255, but ideally I'd like to avoid creating 256 separate macro definitions.M(id,...)
macro itself cannot be changed.The macro CHECK0 works based on the number of tokens encountered in a macro.
If a token passed to the macro has a value of 0, it expands to HIDDEN0 that expands to two tokens. Otherwise it expands to a macro that doesn't exist, and this macro is considered as one token.
The macro SECOND then selects the second token. If HIDDEN0 is encountered, it selects 0, if the non-existing token is encountered, it selects 1.
That result is then joined with a prefix selected by the user. This is seen in macros HELLO, and PRINT. One is a plain macro, the other is a macro function. The resulting macro is either HELLO0 or HELLO1. One is defined as something useful, other is defined as empty. The same goes for PRINT.
#include <stdlib.h>
#include <stdio.h>
#define EXPAND(...) __VA_ARGS__ //needed for MSVC compatibility
#define JOIN_EXPAND( a , b ) a##b
#define JOIN( a , b ) JOIN_EXPAND( a , b )
#define SECOND_EXPAND( a , b , ... ) b
#define SECOND(...) EXPAND( SECOND_EXPAND( __VA_ARGS__ ) )
#define HIDDEN0 unused,0
#define CHECK0( value ) SECOND( JOIN( HIDDEN , value ) , 1 , unused )
#define HELLO0 puts( "HELLO" )
#define HELLO1
#define HELLO( value ) JOIN( HELLO , CHECK0( value ) )
#define PRINT0( ... ) printf( __VA_ARGS__ )
#define PRINT1( ... )
#define PRINT( value , ... ) JOIN( PRINT , CHECK0( value ) )( __VA_ARGS__ )
int main( void )
{
HELLO( 54545 ) ; //evaluates to nothing
HELLO( 1 ) ; //evaluates to nothing
HELLO( 0 ) ; //evaluates to puts( "HELLO" )
PRINT( 861151 , "Some values: %lf %d\n" , 3.13 , 12345 ) ; //evaluates to nothing
PRINT( 1 , "Some values: %lf %d\n" , 3.13 , 12345 ) ; //evaluates to nothing
PRINT( 0 , "Some values: %lf %d\n" , 3.13 , 12345 ) ; //evaluates to printf( "Som
printf( "%d %d %d\n", CHECK0( 0 ) , CHECK0( 1 ) , CHECK0( 123456 ) ) ; //outputs 0 1 1
return EXIT_SUCCESS ;
}
Based almost entirely on @PaulFultzII's superbly detailed answer to this question, here is a way to do this:
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 PROBE(~)
#define BOOL(x) COMPL(NOT(x))
#define IF(c) IIF(BOOL(c))
#define EAT(...)
#define EXPAND(id, ...) printf(__VA_ARGS__, id)
#define M(id, ...) IF(id)(EXPAND(id, __VA_ARGS__), EAT(id, __VA_ARGS__))
M(0, "don't ever print this!\n")
M(1, "ok to print %s, %d\n", "with a string")
M(172, "ok to print %d\n")
If we run this through the preprocessor (cpp
in the case of the GNU C compiler), we get this:
printf("ok to print %s, %d\n", "with a string", 1)
printf("ok to print %d\n", 172)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With