cc-preprocessor

Expand a macro based on its parameter value


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:


Solution

  • 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 ;
    }