Search code examples
cmacrosembeddedavratmega

c preprocessor macro concatenate arguments after expansion


I am writing a driver for avr gpio, I have a function that takes an input which is an enum. I made a macro that calls this function after concatenating the port name with "__" so I can always use 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__:

now when I want to use that function I use: initPort(PORTA,1,...) and this works fine. The problem is when I want to use something like:

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

what happens now is that the argument of GPIO_Init is now LED_PORT__ and not PORTA__

is it possible to fix this or I have to use another way?


Solution

  • You actually can do it by forcing the preprocessor to perform an extra pass before:

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

    This will do:

    1st pass:

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

    2nd pass:

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

    Here is a demo

    Possible pitfall:

    If PORTA is a defined symbol, it will get expanded too on the second pass. So if you have a line such as

    #define PORTA XXX
    

    somewhere in the code, it will expand into

    GPIO_Init(XXX__,1,2,3);