Search code examples
cmacroslookup-tables

Look-up table of C macros


I'm making look-up tables between 2 drivers. I use an enum starting at index 0, which is passed to a look-up table to return an integer. This works fine.

// In library
#define LIB_FEATURE_1 0x10
#define LIB_FEATURE_2 0x22
#define LIB_FEATURE_3 0x44
#define LIB_FEATURE_4 0x42

// In my costum driver
enum features_s {
    my_feature_a = 0,
    my_feature_b = 1,
    my_feature_c = 2
};

const int feature_tbl[] = {
    LIB_FEATURE_2,   // Maps my_feature_a to LIB_FEATURE_2
    0xFF,            // Maps my_feature_b to an error code because this  
                     //     feature is not present in library
    LIB_FEATURE_4    // Maps my_feature_c to LIB_FEATURE_4
};

// In app
int value = feature_tbl[my_feature_a];

The library contains some more complicated macros (setting registers in an embedded system) :

// In library
#define LIB_FEATURE_1 do {
                    //does black magic
                } while(0)

#define LIB_FEATURE_2 do {
                    //does white magic
                } while(0)

#define LIB_FEATURE_3 do {
                    //does yellow magic
                } while(0)

#define LIB_FEATURE_4 do {
                    //does purple magic
                } while(0)

// In my costum driver
enum features_s {
    my_feature_a = 0,
    my_feature_b = 1,
    my_feature_c = 2
};

/* 
 * something missing here. I want this mapping :
 * my_feature_a executes LIB_FEATURE_2();
 * my_feature_b executes nothing
 * my_feature_c executes LIB_FEATURE_4();
 */

// In app
SOME_KIND_OF_LOOK_UP_TABLE[my_feature_a](); 

Is it possible to create a const table, or a macro that takes an index as argument and executes the right feature?

I also tried macro concatenation, but it doesn't seem to work.

I tried using a const table, and a macro concatenations


Solution

  • Runtime version:

    //function prototype
    typedef void (*my_lib_feature_function)();
    
    //implement feature functions
    //we need an address, therefore real functions instead of macros
    static void my_lib_feature_function_1() { /* feature magic 1 */ }
    static void my_lib_feature_function_2() { /* feature magic 2 */ }
    static void my_lib_feature_function_3() { /* feature magic 3 */ }
    static void my_lib_feature_function_4() { /* feature magic 4 */ }
    
    //feature table (lookup table)
    //organize as you see fit, extend or shorten it, but
    //take care of the right indices (enum values)
    static const my_lib_feature_function function_table[] = {
        my_lib_feature_function_2, //index 0 -> my_feature_a
        NULL,                      //index 1 -> my_feature_b
        my_lib_feature_function_4  //index 2 -> my_feature_c
    };
    
    //invoker
    //param feature is the index to the lookup table
    static void invoke_my_lib_feature(enum features_s feature)
    {
        if (function_table[feature] != NULL) //if entry exists
            function_table[feature]();       //execute it
    }
    
    //In app
    /*either*/ //invoke_my_lib_feature(my_feature_a);
    /*and/or*/ //invoke_my_lib_feature(my_feature_b);
    /*and/or*/ //invoke_my_lib_feature(my_feature_c);
    

    Compiletime version:

    //pp util (concatenation)
    #define CAT(A,B) CAT_(A,B)
    #define CAT_(A,B) A##B
    
    //instead of enum (unfortunately, we can't use enum values here)
    #define MY_FEATURE_A 0
    #define MY_FEATURE_B 1
    #define MY_FEATURE_C 2
    
    //feature table
    #define LIB_FEATURE_ENTRY_0 LIB_FEATURE_2 //-> MY_FEATURE_A
    #define LIB_FEATURE_ENTRY_1 //empty       //-> MY_FEATURE_B
    #define LIB_FEATURE_ENTRY_2 LIB_FEATURE_4 //-> MY_FEATURE_C
    
    //invoker
    #define INVOKE_LIB_FEATURE(IDX) CAT(LIB_FEATURE_ENTRY_,IDX)
    
    //In App
    /*either*/ //INVOKE_LIB_FEATURE(MY_FEATURE_A); //expands to text after LIB_FEATURE_2
    /*and/or*/ //INVOKE_LIB_FEATURE(MY_FEATURE_B); //empty
    /*and/or*/ //INVOKE_LIB_FEATURE(MY_FEATURE_C); //expands to text after LIB_FEATURE_4