c预处理器宏在扩展后连接参数

c preprocessor macro concatenate arguments after expansion

我正在为 avr gpio 编写驱动程序,我有一个函数接受一个枚举输入。我制作了一个宏,在将端口名称与“__”连接后调用此函数,因此我始终可以使用 initPort(PORTA,1,...)。

#define initPort(port,mask,dir,pullup) GPIO_Init(port ## __,mask,dir,pullup)

typedef enum {
PORTA__,
PORTB__,
PORTC__,
PORTD__
} PORT;

void GPIO_Init(PORT p, uint8_t pins, Direction dir,uint8_t pullup) {
switch (p) {
    case PORTA__:

现在,当我想使用该函数时,我使用:initPort(PORTA,1,...) 并且它工作正常。 问题是当我想使用类似的东西时:

#define LED_PORT PORTA
initPort(LED_PORT,1,...) 

现在发生的是 GPIO_Init 的参数现在是 LED_PORT__ 而不是 PORTA__

是否可以解决这个问题,或者我必须使用其他方法?

你问的是不可能的。但是,您可以创建一个名为 LED_PORTinitPort() 的函数,并通过将宏的第一个参数连接到 initPort() 来调用它,从而实现相同的目标。

通常的技术是添加一个间接级别,如下所示:

#define PORTNAME(port)     port ## __
#define initPort(port, mask, dir, pullup) GPIO_Init(PORTNAME(port), mask, dir, pullup)

typedef enum {
    PORTA__,
    PORTB__,
    PORTC__,
    PORTD__
} PORT;

void GPIO_Init(PORT p, uint8_t pins, Direction dir, uint8_t pullup)
{
    switch (p)
    {
    case PORTA__:
        break;
    }
}

#define LED_PORT PORTA
initPort(LED_PORT, 1, 9, 43)

这可以预处理(我运行cpp port31.c得到这个输出):

# 1 "port31.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "port31.c"




typedef enum {
    PORTA__,
    PORTB__,
    PORTC__,
    PORTD__
} PORT;

void GPIO_Init(PORT p, uint8_t pins, Direction dir, uint8_t pullup)
{
    switch (p)
    {
    case PORTA__:
        break;
    }
}


GPIO_Init(PORTA__, 1, 9, 43)

这看起来就是您想要的结果。

关于 SO 的其他问题描述了一般技术。

你实际上可以通过强制预处理器在之前执行额外的传递来做到这一点:

#define initPortS(port,mask,dir,pullup) GPIO_Init(port ## __,mask,dir,pullup)
#define initPort(...) initPortS(__VA_ARGS__)
#define LED_PORT PORTA

initPort(LED_PORT,1,2,3);

这样做:

第一遍:

initPort(LED_PORT,1,2,3); -> initPortS(PORTA,1,2,3);

第二遍:

initPortS(PORTA,1,2,3); -> GPIO_Init(PORTA__,1,2,3);

Here is a demo

可能的陷阱:

如果 PORTA 是一个已定义的符号,它也会在第二遍展开。所以如果你有一行

#define PORTA XXX

在代码的某处,它将扩展为

GPIO_Init(XXX__,1,2,3);