简体   繁体   中英

How to force macro to not expand

Using the following code:

#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();
}

How can we define CONCATENATE(x) macro to expand only one layer deep. Using two levels of indirection it would expand all the way to pointer to structure, what I want is to expand UART_PERIPH only one layer and paste it together to form an already existing macro from its argument.

Is this possible?

How can we define CONCATENATE(x) macro to expand only one layer deep. ... Is this possible?

No. Here's what you have available. When macro invocation occurs, the first step is argument substitution (as; 6.10.3.1); during that step, the tokens in the argument are evaluated if their corresponding parameter is mentioned in the macro's replacement list with said mention not being involved in a stringification or paste. The resulting expansion is substituted for said parameters in the replacement list. Next, stringification/pastes are applied in no particular order. Finally, rescan and further replacement (rafr; 6.10.3.4p1) occurs, during which the resulting replacement list itself is scanned; during this scan, the macro's name is "painted blue" (6.10.3.4p2; "blue paint" is not mentioned by name but is technical jargon for this), meaning if it's encountered it will not expand further.

So let's look at it from this point of view. UART_PERIPH is an identifier. Either it will be recognized as a macro in some context (ie, will trigger macro invocation), or it will not. It doesn't matter if the context is during an as or a rafr; if this is invoked, the invocation involves rafr (no as because it's object-like). So the invocation involves taking USART2 and rescanning it. The only possible way for this to not expand USART2 is for this identifier to not be recognized as a macro, but since it's currently defined as one, the only way for that to happen is for this identifier to be painted blue. That's not possible (at least in the intended context) because USART2 would have to be expanding for this to happen, and by that time you're already injecting tokens you don't want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM