Can I define a macro using a macro in C?

I have a set of #defines like this:

#define MODULE1_PINMASK 0x1
#define MODULE2_PINMASK 0x2
#define MODULE3_PINMASK 0x3

      

where the value of the pin mask depends on the second argument:

#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3

      

If at any point in the future I make a change like:

#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */ 

      

I need to change the mask as well:

#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */ 

      

I am trying to automate the process without manually changing the mask. So far I have these macros to extract the second argument of MODULEX_PORT_PIN (in this case, I don't need the first argument):

#define GET_SECOND(X, Y) Y
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN)

      

If I use them in functions, I get the correct result, for example:

uint8_t pinmask=0x0;

switch (GET_PIN(MODULE2_PORT_PIN))
{
    case 1:
        pinmask = 0x1;
        break;
    case 2:
        pinmask = 0x2;
        break;
    case 3:
        pinmask = 0x3;
        break;
    default:
        break;
}

printf ("%#x", pinmask); /* prints "0x2" */

      

but i want to keep pinmasks as #defines. Is there a way to implement a macro #define GET_PINMASK

that uses the switch case to define the finger mask? I am targeting something like:

#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN))

      

which in this case will define MODULE1_PINMASK as 0x1.

EDIT: The second argument in #define MODULE1_PORT_PIN A,1

is a uint8_t, not a hex value, so I can't pass it directly.

+3


source to share


2 answers


I think you can overdo the problem. If the second field of each MODULEn_PORT_PIN

defines an always integer constant expression , then this should work:

#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3

#define GET_SECOND(X, Y) (Y)
#define PIN_TO_MASK(PIN) (1ul << GET_SECOND(PIN))

#define MODULE1_PINMASK PIN_TO_MASK(MODULE1_PORT_PIN)
#define MODULE2_PINMASK PIN_TO_MASK(MODULE2_PORT_PIN)
#define MODULE3_PINMASK PIN_TO_MASK(MODULE3_PORT_PIN)

      



It is not clear from your question if the second field could be anything other than an integer constant expression. If a constant is always present in the second field enum

, then macros MODULEn_PINMASK

can be used in any context other than expressions #if

. If it's ever associated with a variable, then they can only be used inside the function body. (Since this is C, not C ++, this is true even if a variable const

.)

There is no way to avoid having to write each one #define

separately. If this is a problem, you should be thinking about writing a program that generates the list #define

s. Generating source code from a DSL of your own invention at build time is an underrated technique.

+4


source


Are you considering using x-macro ?

You start by creating an abstract #define

for the list of records:

#define CREATE_LIST() \
    ENTRY(1, A, 0x1) \
    ENTRY(2, A, 0x2) \
    ENTRY(3, A, 0x3)

      

And then call the list for different definitions ENTRY

:



// Get the number of entries. Creates something like:
//   const uint8_t PIN_COUNT = 0 + 1 + 1 + 1;
#define ENTRY(number, x, y) + 1
const uint8_t PIN_COUNT = \
    CREATE_LIST()
;
#undef ENTRY

// Array of first parameters
#define ENTRY(number, x, y) #x ,
const char * Pin_names[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

// Array of second parameters
#define ENTRY(number, x, y) y,
const uint8_t Pin_masks[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

// Array of module names
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) ,
const char * Module_names[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

      

The preprocessor will expand it to the following value:

const uint8_t PIN_COUNT =
    + 1 + 1 + 1
;

const char * Pin_names[PIN_COUNT] =
{
    "A" , "A" , "A" ,
};

const uint8_t Pin_masks[PIN_COUNT] =
{
    0x1, 0x2, 0x3,
};

const char * Module_names[PIN_COUNT] =
{
    "MODULE1", "MODULE2", "MODULE3"
};

      

The possibilities are endless. This is less readable, but perhaps a little more convenient.

0


source







All Articles