I am posting this question here after I have done enough research within our community. However, I couldn't find a proper solution for my problem yet. So, I am posting my question here.

#define EXPAND_AS_ENUMERATION(a) CODE_##a,
#define EXPAND_AS_ARRAY(a) a,

#define CODE_TABLE(EXPAND)\
    EXPAND(0x00E30054uL)\
    EXPAND(0x00ED3581uL)\
    EXPAND(0x00ED3983uL)\
    EXPAND(0x00EE0368uL)\
    EXPAND(0x00EE0368uL)\
    EXPAND(0x00D01087uL)\
    EXPAND(0x00ED4181uL)\
    EXPAND(0x00505602uL)\


// Actual Event IDs which need to be selected at run time
#define SWC_FAULT_CODE_0x00E30054_EVENT 113
#define SWC_FAULT_CODE_0x00ED3581_EVENT 213
#define SWC_FAULT_CODE_0x00ED3983_EVENT 432
#define SWC_FAULT_CODE_0x00EE0368_EVENT 411
#define SWC_FAULT_CODE_0x00EE0368_EVENT 311
#define SWC_FAULT_CODE_0x00D01087_EVENT 231
#define SWC_FAULT_CODE_0x00ED4181_EVENT 471
#define SWC_FAULT_CODE_0x00505602_EVENT 419

#define prefix_str SWC_FAULT_CODE
#define postfix_str _EVENT

#define Get_EventID_FROM_CODE(code)         ?????   // ex: when code= 0x00ED3581, then it should return SWC_FAULT_CODE_0x00ED3581_EVENT macro or it's value 213
#define Get_EventID_FROM_ENUM(code_enum)    ?????   // ex: when code_enum= CODE_0x00ED3581, then it should return SWC_FAULT_CODE_0x00ED3581_EVENT macro or it's value 213
#define Get_CodeEnumName(code)              ?????   // ex: when code = 0x00ED3581, then it should return DTC_0x00ED3581 which is enum element

typedef enum
{
    CODE_TABLE(EXPAND_AS_ENUMERATION)
    CODE_COUNT
}codeList_t ;


void Cycle_1ms(const uint32 code)
{
    
    // Based on code value, I want to get the macro value of SWC_FAULT_CODE_0xZZZZZZZZ_EVENT. 
    // ex: when code = 0x00ED3581, then eventID = SWC_FAULT_CODE_0x00ED3581_EVENT = 213
    
    uint16 eventID_FromCode = Get_EventID(code);
    
}

void Cycle_1ms_anotherFunc(codeList_t  code_enum)
{
// Based on code value, I want to get the macro value of SWC_FAULT_CODE_0xZZZZZZZZ_EVENT. 
    // ex: when code = 0x00ED3581, then eventID = SWC_FAULT_CODE_0x00ED3581_EVENT = 213
    uint16 eventID_FromCodeEnum = Get_EventID_FROM_ENUM(code_enum);
}

void callback_func(uint32 code, uint8* buf)
{
    
    // here, based on code value Get_CodeEnumName() should provide the enum element for that code. ex: when code= 0x00ED3581, enum_var = DTC_0x00ED3581
    codeList_t enum_var = Get_CodeEnumName(code);
}

Here, CODE_TABLE will be changed from project to project and number of elements with in this table. After reading several articles and topics on Xmacros, I though of using Xmacros concept here to avoid looping and heavy use of RAM memory .

2

There are 2 best solutions below

5
On

You cannot use X macros with run-time input, they are expanded at compile time. So if you need to do table look-ups based on run-time values, they are not the solution.

You can however use X macros to generate a look-up table and then use a magic number compile-time constant to expand into an enum, which in turn is corresponding to a look-up table index:

#define GET_EVENT_ID(code) LOOKUP[CODE_##code]

The GET_EVENT_ID expands to something like LOOKUP[CODE_0x00ED3581] which is a an array access.

Also the "events" could be bunched together with the codes in the same X macro list even if you don't need to use them in every macro. Also note that you have duplicate items in your X macro list which won't work since you plan to use it for generating unique enum constants. We can change it like this:

#define CODE_TABLE(X)      \
/*  code          event */ \
  X(0x00E30054uL, 113)     \
  X(0x00ED3581uL, 213)     \
  X(0x00ED3983uL, 432)     \
  X(0x00EE0368uL, 411)     \
  X(0x00D01087uL, 231)     \
  X(0x00ED4181uL, 471)     \
  X(0x00505602uL, 419)     \

Then create SWC_FAULTS as enum constants instead of #defines:

// create SWC_FAULT_CODE_0x00ED3581_EVENT constants:
#define SWC_FAULT(code,event) SWC_FAULT_CODE_##code##_EVENT = event,
enum 
{
  CODE_TABLE(SWC_FAULT)
};

And then the enum to use for index of the lookup table:

// create enums like CODE__0x00ED3581:
#define EXPAND_AS_ENUMERATION(code, event) CODE_##code,
typedef enum
{
  CODE_TABLE(EXPAND_AS_ENUMERATION)
  CODE_COUNT
}code_list_t ;

A complete example:

#include <inttypes.h>
#include <stdio.h>

#define CODE_TABLE(X)      \
/*  code          event */ \
  X(0x00E30054uL, 113)     \
  X(0x00ED3581uL, 213)     \
  X(0x00ED3983uL, 432)     \
  X(0x00EE0368uL, 411)     \
  X(0x00D01087uL, 231)     \
  X(0x00ED4181uL, 471)     \
  X(0x00505602uL, 419)     \


// create SWC_FAULT_CODE_0x00ED3581_EVENT constants:
#define SWC_FAULT(code,event) SWC_FAULT_CODE_##code##_EVENT = event,
enum 
{
  CODE_TABLE(SWC_FAULT)
};

// create enums like CODE__0x00ED3581:
#define EXPAND_AS_ENUMERATION(code, event) CODE_##code,
typedef enum
{
  CODE_TABLE(EXPAND_AS_ENUMERATION)
  CODE_COUNT
}code_list_t ;

// create look-up table containing SWC_FAULT_CODE_0x00ED3581_EVENT
// use designated initializers to get [CODE__0x00ED3581] = SWC_FAULT_CODE_0x00ED3581_EVENT
#define LOOKUP_TABLE(code,event) [CODE_##code] = SWC_FAULT_CODE_##code##_EVENT,
static const uint32_t LOOKUP[CODE_COUNT] = 
{
  CODE_TABLE(LOOKUP_TABLE)
};
_Static_assert(sizeof LOOKUP/sizeof *LOOKUP == CODE_COUNT, "LOOKUP table corrupt");


#define GET_EVENT_ID(code) LOOKUP[CODE_##code]

int main()
{
  printf("0x%.8" PRIX32 " = %"PRIu32 "\n", 0x00ED3581uL, GET_EVENT_ID(0x00ED3581uL));

  return 0;
}

Output: 0x00ED3581 = 213.

On gcc x86 the whole table can get optimized out leaving just this:

    mov     edx, 213
    mov     esi, 15545729
    xor     eax, eax
    mov     edi, OFFSET FLAT:.LC0
0
On

You could expand Get_EventID_FROM_CODE as a very long chain of ternary operators (?:). XMacro could be expanded inside the other macro doing the trick.

This would let you avoid using functions. Moreover, the solution accepts any format of integer literal and variables as well. It expands to a true C constant if possible. The only disadvantage is evaluation of the argument expressions but it is a common issue for macros.

#include <inttypes.h>
#include <stdio.h>

#define CODE_TABLE(X, ...)              \
  X(0x00E30054uL, 113, __VA_ARGS__)     \
  X(0x00ED3581uL, 213, __VA_ARGS__)     \
  X(0x00ED3983uL, 432, __VA_ARGS__)     \
  X(0x00EE0368uL, 411, __VA_ARGS__)     \
  X(0x00D01087uL, 231, __VA_ARGS__)     \
  X(0x00ED4181uL, 471, __VA_ARGS__)     \
  X(0x00505602uL, 419, __VA_ARGS__)     \

// expands to -1 for invalid code
#define GET_EVENT_ID_(CODE,ENUM,VAR) (VAR) == (CODE) ? ENUM :
#define GET_EVENT_ID(code_var) (CODE_TABLE(GET_EVENT_ID_, code_var) -1)

int main()
{
#define DBG(CODE) \
  printf("%s 0x%08lx = %d\n", #CODE, (unsigned long)(CODE), GET_EVENT_ID(CODE))

  DBG(0x00ED3983uL);
  DBG(0x00ED3983);
  DBG(0xED3983);
  int32_t x = 0x00D01087uL;
  DBG(x);

  // expand to a true constant if possible
  struct X { char x[GET_EVENT_ID(0xED3983)]; };
  printf("%zi\n", sizeof(struct X));

  return 0;
}

Produces an expected output of:

0x00ED3983uL 0x00ed3983 = 432
0x00ED3983 0x00ed3983 = 432
0xED3983 0x00ed3983 = 432
x 0x00d01087 = 231
432