根据其参数值展开宏

Rya*_*ert 12 c c-preprocessor

我有一个看起来像这样的宏:

M(id,...)
Run Code Online (Sandbox Code Playgroud)

如果有id == 0别的话,我希望它扩展到什么都没有.

这可能吗?如果是这样,怎么样?

我的第一直觉是尝试这样的事情:

#define M(id,...) M##id(__VA_ARGS__)
#define M0(...)
#define M_NOT_0(...) some_code(__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

但是这里的最后一行显然是无效的,我无法找到使这种模式有效的方法.

笔记:

  • id是一个0到255之间的整数,但理想情况下我想避免创建256个单独的宏定义.
  • 请不要挑战问题的前提.该M(id,...)宏本身不能改变.
  • 不能对可扩展的最终代码做出任何假设.

Edw*_*ard 5

几乎完全基于 @PaulFultzII 对这个问题的非常详细的回答,这里有一种方法可以做到这一点:

#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")
Run Code Online (Sandbox Code Playgroud)

如果我们通过预处理器运行它(cpp在 GNU C 编译器的情况下),我们会得到:

printf("ok to print %s, %d\n", "with a string", 1)
printf("ok to print %d\n", 172)
Run Code Online (Sandbox Code Playgroud)


250*_*501 5

宏CHECK0根据宏中遇到的令牌数量工作.

如果传递给宏的标记的值为0,则会扩展为HIDDEN0,扩展为两个标记.否则,它会扩展为不存在的宏,并且此宏被视为一个标记.

宏SECOND然后选择第二个令牌.如果遇到HIDDEN0,则选择0,如果遇到不存在的令牌,则选择1.

然后,该结果与用户选择的前缀相结合.这可以在宏HELLO和PRINT中看到.一个是普通的宏,另一个是宏功能.生成的宏是HELLO0或HELLO1.一个被定义为有用的东西,另一个被定义为空.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 ;
}
Run Code Online (Sandbox Code Playgroud)