Как заставить макрос не расширяться - PullRequest
2 голосов
/ 14 июня 2019

Используя следующий код:

#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 Ответ

3 голосов
/ 14 июня 2019
Как мы можем определить макрос CONCATENATE (x) для расширения только на один слой.... Возможно ли это?

Нет.Вот что у вас есть в наличии.Когда происходит вызов макроса, первым шагом является замена аргумента (как; 6.10.3.1);во время этого шага токены в аргументе оцениваются, если их соответствующий параметр упоминается в списке замены макроса, причем упомянутое упоминание не участвует в строковом преобразовании или вставке.Полученное расширение заменяет указанные параметры в списке замены.Далее стренификация / вставки применяются в произвольном порядке.Наконец, происходит повторное сканирование и дальнейшая замена (rafr; 6.10.3.4p1), во время которой сканируется сам список получаемых замен;во время этого сканирования имя макроса «закрашено синим» (6.10.3.4p2; «синяя краска» не упоминается по имени, но для этого используется технический жаргон ), что означает, что при обнаружении он не будет расширяться дальше.

Итак, давайте посмотрим на это с этой точки зрения.UART_PERIPH - это идентификатор.Либо он будет распознан как макрос в некотором контексте (то есть вызовет вызов макроса), либо не будет.Не имеет значения, находится ли контекст во время as или rafr;если это вызывается, вызов включает rafr (нет как, потому что он подобен объекту)Таким образом, вызов включает в себя USART2 и повторное сканирование.Единственный возможный способ не расширять USART2 - это чтобы этот идентификатор не был распознан как макрос, но поскольку он в настоящее время определен как единое целое, единственный способ для этого - закрасить этот идентификатор синим цветом.Это невозможно (по крайней мере, в предполагаемом контексте), потому что USART2 должно быть расширено, чтобы это произошло, и к тому времени вы уже вводите токены, которые вам не нужны.

...