0

I have a set of #defines like that:

#define PORTA port_a
#define PORTB port_b
#define PORTC port_c

And some re-definitions of these into:

#define MY_PORT1 PORTA
#define MY_PORT2 PORTB
#define MY_PORT3 PORTC

And also a series of xxx_set(param1, param2) functions where xxx belongs to each PORTx, so:

PORTA_set(param1, param2)
PORTB_set(param1, param2)
PORTC_set(param1, param2) 

I need to call these functions but using a single one, with my "custom port name" as the first parameter, so example:

set(MY_PORT1, param1, param2) must expand to PORTA_set(param1, param2), and so on.

I tried after reading several similar questions, related to expansion of macros into concatenations:

#define CAT_I( x, y ) x ## y
#define CAT( x, y ) CAT_I( x, y )
#define set( port, param1, param2 ) CAT( port, _set )(param1, param2)

But this throws me error

expected ';' before '_set'
pasting ")" and "_set" does not give a valid preprocessing token

What am I missing?

TheUnexpected
  • 3,077
  • 6
  • 32
  • 62
  • `pasting ")" and "_set"` what does `port_a` expand to? Is there no "in expansion of.. in expansion of..." messages? Are there no "file:line:column" in error messages? Please post the full error message. – KamilCuk May 27 '21 at 18:17

3 Answers3

0

I think you've just got too many macros. Not sure why the token pasting examples all use macros called CAT. I don't think it helps, and it seems to be adding excessive complexity.

#define setport( port, param1, param2 ) port##_set(param1, param2) ought to work.

Note that it's a bad idea to use set as the name of a macro and part of the definition. That's why this macro is called setport

Tim Randall
  • 4,040
  • 1
  • 17
  • 39
0

It seems like you have:

#define port_a (something something)

which then does not work, because preprocessor can't concatenate ) with _set. No, you can't "halfway" expand a macro.

But why write all these PORT all the time. Just write the letters.

#define PORTA port_a
#define PORTB port_b
#define PORTC port_c

#define MY_PORT1   A
#define MY_PORT2   B
#define MY_PORT3   C

#define _set_in(x) PORT##x##_set
#define set(port, param1, param2)  _set_in(port)(param1, param2)
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • This is the most acceptable for my situation. And yes, "port_a" was a way to simplify my code, but in reality it is a variable wrapped into "( )". Now it is clear and I've followed your suggestion regarding the single letters. – TheUnexpected May 28 '21 at 07:42
0

I need to call these functions but using a single one, with my "custom port name" as the first parameter

If that is the purpose, you might want to consider a different approach, which uses C11 generic selection:

#include <stdio.h>

// Define some helper types or tags.
typedef struct PORTA PORTA;
typedef struct PORTB PORTB;
typedef struct PORTC PORTC;

typedef PORTA port_a;
typedef PORTB port_b;
typedef PORTC port_c;

typedef PORTA MY_PORT1;
typedef PORTB MY_PORT2;
typedef PORTC MY_PORT3;

// The actual functions to be called:
void PORTA_set(int a, int b) {
    printf("PORT A   args: %d %d\n", a, b);
}

void PORTB_set(int a, int b) {
    printf("PORT B   args: %d %d\n", a, b);
}

void PORTC_set(int a, int b) {
    printf("PORT C   args: %d %d\n", a, b);
}

// Macroes that perform the selection:
#define set_impl(X, a, b) _Generic( X, \
                                    PORTA*: PORTA_set, \
                                    PORTB*: PORTB_set, \
                                    PORTC*: PORTC_set \
)(a, b)

#define set_(type, a, b) set_impl((type *)NULL, (a), (b))

int main(void)
{
    // Calls with the wanted interface.
    set_(port_a, 0, 1);
    set_(MY_PORT2, 42, 17);
    set_(PORTC, 8, 99);

    // Direct call example.
    PORTC_set(-3, 0);
}

Testable here.

Bob__
  • 12,361
  • 3
  • 28
  • 42