是否可以定义将按以下方式扩展的预处理器宏。
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
)
我可以像前者一样被转化为后者。如果在预处理器规则中不可能,没有什么大不了的,我会和它一起生活,但如果是的话,我想知道这个技巧。
答案 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编译器会将你的整个程序视为一行,这会对某些错误报告造成影响 - 尽管你已经解决了这个问题的一半,因为每个声明块如果原始版本有效,似乎也只有一行。