在带双括号的宏函数中使用预处理器条件

Using preprocessor conditionals in macro functions with double parentheses

鉴于:

#define TRACE(x) do { if (DEBUG) dbg_print x; } while (0)

我要:

TRACE((
    "Message: %s"
#ifdef MYDEF
    "Additional stuff"
#endif
    , msg));

但是报错:

error C2121: '#' invalid character : possibly the result of a macro expansion
error C2146: syntax error : missing ')' before identifier 'ifdef'
error C2121: '#' invalid character : possibly the result of a macro expansion
error C2059: syntax error : ')'

我知道我可以通过编写两个不同的 TRACE 调用并使用 #ifdef...#else...#endif 轻松解决此问题,但以上只是一个简化的案例。我的实际用例涉及控制格式字符串和参数的多个 #ifdef,因此编写多个跟踪调用是不切实际的(例如,使用 3 ifdef,我需要 2^3 = 8 个不同的调用照顾所有可能的组合)。有解决办法吗?

一些编译器会通过编译器扩展来编译你的代码,但它是不可移植的。您可以通过有条件地定义另一个宏并在调用 TRACE 中使用其结果来解决此问题,如下所示:

#ifdef MYDEF
#define IF_MY(x,y) x y
#else
#define IF_MY(x,y) x
#endif

现在你可以这样写你的TRACE

TRACE((IF_MY("Message: %s", "Additional stuff"), msg));

Demo #1.

it seems like it will run into scalability issues.

这种印象是不正确的。您可以很容易地将这种方法扩展到任意数量的变量,而无需 运行 组合爆炸。这是添加第二个变量的示例:

#ifdef YOURDEF
#define IF_MY_YOUR(x,y,z) IF_MY(x,y) z
#else
#define IF_MY_YOUR(x,y,z) IF_MY(x,y)
#endif

现在您可以在 TRACE:

中使用组合宏
TRACE((IF_MY_YOUR("Message: %s", "Additional stuff", "More stuff"), msg));

Demo #2 - Both MYDEF and YOURDEF are defined

Demo #2 - Only YOURDEF is defined

Demo #2 - Only MYDEF is defined

Demo #2 - Neither MYDEF or YOURDEF is defined

What if I have additional arguments that are to be controlled by #define too?

对参数做同样的事情,在 xy 部分之间用逗号分隔。 TRACE 的调用如下所示:

TRACE((
    IF_MY_YOUR_FMT("Message: %s", "Additional %s stuff", "More %s stuff")
,   IF_MY_YOUR_ARG(msg1, msg2, msg3)
));