cfunction-pointersjump-table

Array of jump tables in C


I'm trying to optimize access to some jump tables I have made, they are as follows:

int (*const usart_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};

int (*const usart_frame_table[USART_READ_WRITE_CLEAR])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};

int (*const usart_trig_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};

As you can see, the functions are for accessing a usart peripheral on a hardware level and are arranged in the table in the order of read/write/clear.

What I am attempting to do is have another jump table of jump tables, this way I can either run through initializing all the usart's registers in startup or simply change a single register later if desired.

i.e.

<datatype> (*usart_peripheral_table[<number of jump tables>])() = 
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};

This way I can expose that table to my middleware layer, which will help maintain a standard across changing HALs, and also I can use a define to index this table i.e.

fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);

As you may have already guessed, I am struggling to figure out how to construct this table. I figured it is one of two things:

  1. Another simple array of pointers, as even a jump table itself is just an array of pointers. Hence my initialization would be:

    const int* (*usart_peripheral_table[<number of jump tables])() = 
    {usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
    

However this doesn't seem to be working. Then I thought:

  1. An array of pointers to pointers. So I tried all kinds of combos:

     const int**(*usart_perip...
    
    
     const int**(usart_perip...
    
    
    const int** (*usart_peripheral_table[<number of jump tables])() = 
    {&usart_ctrl_table, &usart_frame_table[0], usart_trig_ctrl_table};
    

Nothing seems to work. Do I need to store the address of the lower jump tables in yet another pointer before assigning that variable to a pointer-to-pointer array? i.e.

    int* fn_ptr = usart_ctrl_table;


    <dataytype>(*const usart_periph[<number>])() = {fn_ptr};

Thanks in advance, any help would be greatly appreciated.

MM25

EDIT:

const int** (*const peripheral_table[1])() =
{&usart_ctrl_table[0]};


const int** (*const peripheral_table[1])() =
{usart_ctrl_table};

The above both give the error "initialization from incomaptible pointer type", as do all other combinations I have tried


Solution

  • Just add a * like you added [] when defining an array.

    int zg_usartCtrlRead();
    int zg_usartCtrlWrite();
    int zg_usartCtrlClr();
    int zg_usartFrameRead();
    int zg_usartFrameWrite();
    int zg_usartFrameClr();
    int zg_usartTrigctrlRead();
    int zg_usartTrigctrlWrite();
    int zg_usartTrigctrlClr();
    
    int (*const usart_ctrl_table[])() =
    {zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
    
    int (*const usart_frame_table[])() =
    {zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
    
    int (*const usart_trig_ctrl_table[])() =
    {zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
    
    int (* const * const usart_peripheral_table[])() = 
    {usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
    

    Usage:

    usart_peripheral_table[1][2](5, 1, 3, 5, 6);
    

    Btw, an empty parameter list on function declaration () means unspecified number and type of arguments. Do (void) if you want no arguments passed to your function.

    This:

    const int* (*usart_peripheral_table[<number of jump tables])();
    

    Is an array of functions pointers that take unspecified number of arguments and return a pointer to constant integer.

    This:

    const int** (*usart_peripheral_table[<number of jump tables])() 
    

    Is an array of function pointers that take unspecified number of arguments and return a pointer to a pointer to a constant integer.

    You can also go with a 2D array:

    int (* const usart_peripheral_table_2d[][3])() = {
        {
            zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr, 
        }, {
            zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr,
        }, {
            zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr,
        },
    };
    

    But maybe you want to write accessor functions that will return a pointer to an array of functions. Nothing simpler!

    #include <stddef.h>
    
    int (*usart_ctrl_table_get(size_t idx))() {
        return usart_ctrl_table[idx];
    }
    
    int (*usart_frame_table_get(size_t idx))() {
        return usart_frame_table[idx];
    }
    
    int (*usart_trig_ctrl_table_get(size_t idx))() {
        return usart_trig_ctrl_table[idx];
    }
    
    int (* const (* const usart_peripheral_table_indirect[])(size_t))() = {
        usart_ctrl_table_get, 
        usart_frame_table_get,
        usart_trig_ctrl_table_get,
    };
    

    Usage sample:

    int main() {
        usart_peripheral_table_indirect[2](1)();
    }