组合宏会产生错误

时间:2019-08-16 09:19:17

标签: c c-preprocessor avr

我想用C预处理器和给定的接口名称生成AVR中断向量的名称。因此,我有了这个配置文件(Config.h),该文件包含在另一个头文件中。

#define INTERFACE                   C, 0
#define BAUD                        19200

和此宏以获取ISR名称

#include "Config.h"
#define ISR_NAME(Name, Vector)      USART ## C0 ## _ ## Vector ## _vect

我的代码中使用了此宏

#include "Config.h"

ISR(ISR_NAME(INTERFACE, RXC))
{
    // Some stuff
}

,效果很好。但是接口的名称应根据给定的INTERFACE进行设置,为此,我将宏ISR_NAME更改为以下内容

#include "Config.h"
#define CATENATE(Prefix, Index)             Prefix ## Index
#define ISR_NAME(Name, Vector)              USART ## CATENATE(Name) ## _ ## Vector ## _vect

像以前一样使用宏

#include "Config.h"

ISR(ISR_NAME(INTERFACE, RXC))
{
    // Some code
}

此解决方案会产生大量警告和错误

Severity    Code    Description Project File                                Line
Message     in expansion of macro 'ISR_NAME'                                ...
Message     in expansion of macro 'ISR_NAME'                                ...
Message     in expansion of macro 'ISR_NAME'                                ...
Message     in expansion of macro 'INTERFACE'                               ...
Message     in expansion of macro 'INTERFACE'                               ...
Error       expected ')' before numeric constant    File                    ...
Error       expected ')' before numeric constant    File                    ...
Error       recipe for target 'File.o' failed   File                        ...
Error       pasting ")" and "_" does not give a valid preprocessing token   ...

这是怎么回事?为什么这个额外的宏会产生此错误?

1 个答案:

答案 0 :(得分:1)

此错误消息“清楚地”描述了问题

Error       pasting ")" and "_" does not give a valid preprocessing token

适用于此扩展:

USART ## CATENATE(Name) ## _ ## Vector ## _vect

(“很明显”在这里是个笑话。该错误已被清楚地描述,但是您需要筛选大量的糠ff以找到有用的错误消息。)

查看该行时,您会看到CATENATE(Name)被串联到_。但这不是预处理器所看到的,因为令牌粘贴操作符##在重新扫描替换文本以进行进一步的宏扩展之前之前被应用。预处理器看到的是) ## _,正如指出的那样,它不会产生合法令牌。 (预处理器还加入了USART ## CATENATE,产生了合法但未定义的令牌USARTCATENATE,它没有引起您的警告。但这可能会导致其他错误,从而产生其他错误。)

如果要标记粘贴宏扩展的结果,无论是简单的宏扩展还是函数式的宏扩展,都需要使用间接的令牌粘贴宏,例如CATENATE

#define ISR_NAME(Name, Vector) \
  CATENATE(USART, CATENATE(CATENATE(Name), CATENATE(_, CATENATE(Vector, _vect))))

当然,这将完全对NameVector进行宏扩展,这可能并不是您想要的。要获得所需的内容,您需要清楚使用###运算符的函数式宏的宏扩展顺序:

  1. 宏参数将替换为调用中的参数,但那些出现在###运算符中的参数除外。在替换之前,参数已完全展开。

  2. 应用了###运算符。

    • # 必须后跟一个宏参数名称;相应的参数将转换为字符串文字,而无需对该参数执行任何宏扩展。
    • 如果参数出现在##之前或之后,则该参数将由其对应的参数替换,再次不执行任何宏扩展。 (如果替换的参数对应于一个空参数,那么将插入一个特殊的空占位符。)然后,每次出现由##分隔的两个标记(或占位符)时,都会用一个新的标记替换,该标记表示两个原始标记的串联令牌。
  3. 最后,重新扫描生成的替换文本以进行宏扩展。

在(重新)扫描过程中会识别出类似于函数的宏参数,这就是CATENATE(INTERFACE)在宏定义内按预期工作的原因(在不兼容的C预处理程序(例如历史性MSVC实现)上除外)的原因,但是不在最高层。

相关问题