C预处理器宏自行扩展

时间:2020-06-28 05:08:22

标签: c gcc c-preprocessor

我相信我的问题的答案与C Preprocessor, Stringify the result of a macro有关。但是,我在将解决方案应用于用例时遇到了麻烦。

我有这个功能:

astNodePtr createNode(int lineno, int nodeType, ...);

我有一个与之配套的宏:

#define NODE(nodeType, ...) createNode(yylineno,nodeType,##__VA_ARGS__)

一切正常,直到出现这样的一行:

NODE(1,x,NODE(2,y,z))

我的链接器给我一个错误:undefined reference to 'NODE'

编辑:

我已经尝试过(受上述链接的启发)

#define EXPAND(x) ##x
#define NODE(nodeType, ...) createNode(yylineno,nodeType, EXPAND(__VA_ARGS__))

但是,我遇到了同样的错误。

编辑:

我应该提到,我也因此使用了宏:NODE(5)

因此,为了避免尾随逗号问题,我需要在##前面加上__VA_ARGS__

2 个答案:

答案 0 :(得分:3)

摆脱宏主体中的##。这阻碍了嵌套调用的扩展。即尝试:

#define NODE(nodeType, ...) createNode(yylineno,nodeType,__VA_ARGS__)

更新:现在,对您的问题进行编辑,我了解了这一需求 宏中的##。克里斯·多德(Chris Dodd)的解决方案解决了这个问题 问题很好。

这是另一种方法。该解决方案增加了一层扩展 在顶层处理嵌套宏,然后处理 较低级别的尾随逗号问题:

#define NODE2(nodeType, ...) createNode(yylineno,nodeType,##__VA_ARGS__)
#define NODE(...) NODE2(__VA_ARGS__)

这将根据需要处理以下示例案例,没有结尾 逗号:

NODE(a,NODE(b,c))
NODE(x)
NODE(NODE(y))

此方法的优点是它更通用。 特别是,即使没有强制性的nodeType,它也将起作用 论据。例如,如果名称更改为FOO,并且 取消了nodeType参数,以下方法将起作用:

#define FOO2(...) createNode(yylineno,##__VA_ARGS__)
#define FOO(...) FOO2(__VA_ARGS__)

这将处理以下示例情况,并且不使用结尾逗号:

FOO(FOO(b))
FOO()
FOO(FOO())

答案 1 :(得分:2)

您实际上只需要

#define NODE(...) createNode(yylineno, __VA_ARGS__)

问题在于,使用##还会阻止替换前__VA_ARGS__参数中宏的扩展,并且尽管宏可以在替换后被扩展,但是它们不能递归扩展,因此如果要在另一个NODE宏的参数中包含NODE宏,则不能使用##。幸运的是,您可以避免##摆脱NODE调用中尾随逗号的需要,而不必使用额外的参数(无论如何这都是非标准的gcc扩展名),方法是始终为该参数至少使用一个...-nodeType参数。