将参数前置到列表并在C预处理器宏中应用另一个宏

时间:2014-04-30 10:11:32

标签: c++ c c-preprocessor

是否可以定义将按以下方式扩展的预处理器宏。

MACRO1(x) (y,z,w)
--> MACRO2(x,y,z,w)

MACRO1的扩展能否以某种方式消耗宏调用后列表的左括号,并将其替换为MACRO2(x,,以便预处理器接受结果作为有效的宏调用(假设为{{ 1}}已定义)并且不会引发MACRO2错误?

我试图做这样的事情

unterminated argument list

这样称呼:

#define STRANGE_MACRO(...) __VA_ARGS__
#define STRIP_PAREN(...) __VA_ARGS__)
#define PREPEND_AND_APPLY_STRANGE(x) STRANGE_MACRO(x,STRIP_PAREN

产生PREPEND_AND_APPLY_STRANGE(x) (y,z,w) 错误。有没有办法让它发挥作用?

至于我想要有这种行为的原因,这是出于问题,我认为像这样的宏调用看起来更好

unerminated argument list

大于

MACRO1(identifier) (
    more
    complex
    arguments
)

我可以像前者一样被转化为后者。如果在预处理器规则中不可能,没有什么大不了的,我会和它一起生活,但如果是的话,我想知道这个技巧。

1 个答案:

答案 0 :(得分:3)

如果要在替换列表中包含不匹配的左括号,则需要添加一个间接层:

#define LPAREN (

#define PREPEND_AND_APPLY_STRANGE(x) STRANGE_MACRO LPAREN x,STRIP_PAREN

这样,在正确的语法完成之前,括号不会被视为调用的一部分。

不幸的是,这种技术的局限性是:当STRANGE_MACRO的呼叫完全构建时,它已经过了可以重新扫描的点 - 从开始到结束表达式是在两个不同的调用中构建的,它们发生在同一级别,整个事情从未出现在一个重新扫描列表中 - 并且永远不会实际扩展;您只需在输出中转储STRANGE_MACRO ( x,y,z,w)。您需要在顶层强制重新扫描:

#define EXPAND(...) __VA_ARGS__

宏没有做​​任何事情,但确实意味着它的参数将作为一个完整的单元放入重新扫描列表中,并最终扩展。因此,您可以获得所需语法的最接近的是:

EXPAND(

MACRO1(identifier) (
    ....
)
MACRO1(identifier) (
    ....
)

)

...因此,您不需要使用自己的EXPAND来修改每个自定义块,但您需要将整个程序包装在一个中。并且不能通过在#include中放置EXPAND指令来隐藏包装器,因为指令不会出现在调用中。 (尽管如此,也许你可以通过重新发明namespace或类似语法可能需要的东西来创造一些有用的东西。)

这也有一个缺点,就是C编译器会将你的整个程序视为一行,这会对某些错误报告造成影响 - 尽管你已经解决了这个问题的一半,因为每个声明块如果原始版本有效,似乎也只有一行。