Search code examples
cmultidimensional-arrayfunction-pointerstypedefdesignated-initializer

What is this ```typedef``` declaration?


I was researching about state machines using C, and I ran into this code from this site. There is some typedef declaration that I had never seen before:

    typedef eSystemState (*const afEventHandler[last_State][last_Event])(void); 

and it is used here:

    // Table to define valid states and event of finite state machine
    static afEventHandler StateMachine =
    {
        [Idle_State] ={[Card_Insert_Event]= InsertCardHandler },
        [Card_Inserted_State] ={[Pin_Enter_Event] = EnterPinHandler },
        [Pin_Eentered_State] ={[Option_Selection_Event] = OptionSelectionHandler},
        [Option_Selected_State] ={[Amount_Enter_Event] = EnterAmountHandler},
        [Amount_Entered_State] ={[Amount_Dispatch_Event] = AmountDispatchHandler},
    };

Can somebody please explain what this is? Here is the full code

#include <stdio.h>

//Different state of ATM machine
typedef enum
{
    Idle_State,
    Card_Inserted_State,
    Pin_Eentered_State,
    Option_Selected_State,
    Amount_Entered_State,
    last_State
} eSystemState;

//Different type events
typedef enum
{
    Card_Insert_Event,
    Pin_Enter_Event,
    Option_Selection_Event,
    Amount_Enter_Event,
    Amount_Dispatch_Event,
    last_Event
} eSystemEvent;

//typedef of 2d array
typedef eSystemState (*const afEventHandler[last_State][last_Event])(void);

//typedef of function pointer
typedef eSystemState (*pfEventHandler)(void);

//function call to dispatch the amount and return the ideal state
eSystemState AmountDispatchHandler(void)
{
    return Idle_State;
}

//function call to Enter amount and return amount enetered state
eSystemState EnterAmountHandler(void)
{
    return Amount_Entered_State;
}

//function call to option select and return the option selected state
eSystemState OptionSelectionHandler(void)
{
    return Option_Selected_State;
}

//function call to enter the pin and return pin entered state
eSystemState EnterPinHandler(void)
{
    return Pin_Eentered_State;
}

//function call to processing track data and return card inserted state
eSystemState InsertCardHandler(void)
{
    return Card_Inserted_State;
}

int main(int argc, char *argv[])
{
    eSystemState eNextState = Idle_State;
    eSystemEvent eNewEvent;

// Table to define valid states and event of finite state machine
    static afEventHandler StateMachine =
    {
        [Idle_State] ={[Card_Insert_Event]= InsertCardHandler },
        [Card_Inserted_State] ={[Pin_Enter_Event] = EnterPinHandler },
        [Pin_Eentered_State] ={[Option_Selection_Event] = OptionSelectionHandler},
        [Option_Selected_State] ={[Amount_Enter_Event] = EnterAmountHandler},
        [Amount_Entered_State] ={[Amount_Dispatch_Event] = AmountDispatchHandler},
    };

    while(1)
    {
        // assume api to read the next event
        eSystemEvent eNewEvent = ReadEvent();
        //Check NULL pointer and array boundary
        if( ( eNextState < last_State) && (eNewEvent < last_Event) && StateMachine[eNextState][eNewEvent]!= NULL)
        {
            // function call as per the state and event and return the next state of the finite state machine
            eNextState = (*StateMachine[eNextState][eNewEvent])();
        }
        else
        {
            //Invalid
        }
    }
    return 0;
}

Solution

  • Let's consider the typedef

    typedef eSystemState (*const afEventHandler[last_State][last_Event])(void);
    

    step by step.

    This

    afEventHandler[last_State][last_Event]
    

    declares a two dimensional array. Taking into account that the enumerators last_State and lastEvent are equal to 5 then the above record is equivalent to

    afEventHandler[5][5]
    

    This

    *const afEventHandler[last_State][last_Event]
    

    declares a two-dimensional array of constant pointers (the pointers themselves are constant).

    And at last this

    typedef eSystemState (*const afEventHandler[last_State][last_Event])(void);
    

    declares a two-dimensional array of constant pointers to functions of the type eSystemState ( void ). That is the function has the return type eSystemState and the parameter list void.

    Thus the name afEventHandler is a synonym for the type of a two-dimensional array of constant pointers to functions of the type eSystemState ( void )

    As for this declaration

    // Table to define valid states and event of finite state machine
    static afEventHandler StateMachine =
    {
        [Idle_State] ={[Card_Insert_Event]= InsertCardHandler },
        [Card_Inserted_State] ={[Pin_Enter_Event] = EnterPinHandler },
        [Pin_Eentered_State] ={[Option_Selection_Event] = OptionSelectionHandler},
        [Option_Selected_State] ={[Amount_Enter_Event] = EnterAmountHandler},
        [Amount_Entered_State] ={[Amount_Dispatch_Event] = AmountDispatchHandler},
    };
    

    Then an array of the type described above is declared and initialized using designated initializers.

    Here is a much more simplified example of a similar typedef declaration of a one-dimensional array of function pointers using an enumeration.

    #include <stdio.h>
    
    typedef enum { Add, Subtract, Multiply, Divide, TotalOperations } Operation;
    
    typedef int ( * const Action[TotalOperations] )( int, int );
    
    int add( int x, int y )      { return x + y; }
    int subtract( int x, int y ) { return x - y; }
    int multiply( int x, int y ) { return x * y; }
    int divide( int x, int y )   { return x / y; }
    
    int main(void) 
    {
        Action action =
        {
            [Add] = add, [Subtract] = subtract, [Multiply] = multiply, [Divide] = divide
        };
        
        int x = 100, y = 5;
        
        for ( int i = 0; i < TotalOperations; i++ )
        {
            printf( "%d\n", action[i]( x, y ) );
        }
        
        return 0;
    }
    

    The program output is

    105
    95
    500
    20