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

时间:2015-01-28 08:25:20

标签: c syntax c-preprocessor preprocessor-directive

假设:

#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个不同的调用来处理所有可能的组合)。有办法解决这个问题吗?

1 个答案:

答案 0 :(得分:4)

有些编译器会通过编译器扩展编译代码,但它不可移植。您可以通过有条件地定义另一个宏来解决此问题,并在调用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.

  

似乎会遇到可扩展性问题。

这种印象不正确。你可以很容易地将这种方法扩展到你想要的任意数量的变量,而不会遇到组合爆炸。以下是添加第二个变量的示例:

#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

  

如果我还有其他要由#define控制的参数怎么办?

对参数执行相同操作,在xy部分之间使用逗号。 TRACE的调用如下所示:

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