如何强制宏不展开

时间:2019-06-14 14:56:41

标签: c gcc macros c-preprocessor

使用以下代码:

#include <stdio.h>

typedef struct
{
    int APB1ENR;
    int b;
    int c;
} RCC_TypeDef;

typedef struct
{
    int a;
    int b;
    int c;
} USART_TypeDef;

#define USART2_BASE                     0x1000
#define USART2                          ((USART_TypeDef *) USART2_BASE)
#define RCC_BASE                        0x2000
#define RCC_APB1ENR_USART2EN_Pos        (17U)
#define RCC_APB1ENR_USART2EN_Msk        (0x1UL <<   RCC_APB1ENR_USART2EN_Pos)
#define RCC_APB1ENR_USART2EN            RCC_APB1ENR_USART2EN_Msk
#define RCC                             ((RCC_Typedef *) RCC_BASE)
#define SET_BIT(REG, BIT)               ((REG) |= (BIT))
#define __HAL_RCC_USART2_CLK_ENABLE()   SET_BIT(RCC->APB1ENR, (RCC_APB1ENR_USART2EN))

#define UART_PERIPH     USART2

#define CONCATENATE(x)  // What comes here??

int main()
{
    CONCATENATE(UART_PERIPH);
    // | should expand to __HAL_RCC_USART2_CLK_ENABLE();
}

我们如何定义CONCATENATE(x)宏以仅扩展一层深度。使用两个间接级别,它将一直扩展到结构指针,我想要的是仅扩展UART_PERIPH一层并将其粘贴到一起,以根据其参数形成一个已经存在的宏。

这可能吗?

1 个答案:

答案 0 :(得分:3)

我们如何定义CONCATENATE(x)宏以仅扩展一层深度。 ...这可能吗?

不。这是您所拥有的。发生宏调用时,第一步是参数替换(a.s .; 6.10.3.1);在该步骤中,如果在宏的替换列表中提到了它们的相应参数,而字符串或粘贴中没有提及,则对参数中的标记进行评估。生成的扩展将替换替换列表中的所述参数。接下来,不按特定顺序应用串化/粘贴。最后,重新扫描并进行进一步替换(r.a.f.r; 6.10.3.4p1),在此期间,将扫描生成的替换列表本身;在此扫描过程中,宏的名称为“涂成蓝色”(6.10.3.4p2;“蓝色涂成”的名称未提及,但technical jargon),这意味着如果遇到该宏,它将不会进一步扩展。

所以让我们从这个角度来看它。 UART_PERIPH是一个标识符。在某些情况下它将被识别为宏(即将触发宏调用),否则将不会。上下文是否在a.s中都没有关系。或r.a.f.r .;如果调用此命令,则调用涉及r.a.f.r。 (不可以,因为它是类似对象的)。因此,调用涉及获取USART2并重新扫描。不扩展USART2的唯一可能方法是不将该标识符识别为宏,但是由于当前已将其定义为宏,因此唯一的实现方式是将该标识符涂成蓝色。这是不可能的(至少在预期的情况下),因为USART2必须进行扩展才能做到这一点,并且到那时您已经在注入不需要的令牌。