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

时间:2018-01-26 16:44:50

标签: c macros embedded avr atmega

我正在为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__

是否有可能解决这个问题,或者我必须采用其他方式?

3 个答案:

答案 0 :(得分:1)

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

#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的其他问题描述了一般技术。

答案 1 :(得分:1)

你实际上可以通过强制预处理器执行额外的传递来实现它:

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

答案 2 :(得分:0)

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