我有一个看起来像这样的宏:
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,...)宏本身不能改变.几乎完全基于 @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)
宏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)