Function pointer in C, applications you should know

c function pointer

In the C function pointer is used to resolve the run time-binding. A function pointer is a pointer that stores the address of the function and invokes the function whenever required.

I have already written an article that explains how is the function pointer work in C programming. If you are the then it is my advice that before reading this article you should read my article How to use a function pointer in C?

In this blog post, I will explain the application of the function pointer in C programming. I hope this article will helpful for you and you will understand where you can use the function pointer in C code. So without wasting your time lets come on the topic application of the function pointer in C programming.

 

Call-back function:

We can implement the call-back function using the function pointer in the C programming. A call-back function is important for any programing language.

In programming, a callback function is any executable code that is passed as an argument to other code that is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.

Generally, the call-back function is used in library API because the library API is not only used by the library creator but it can also be used by the third person. If you will use a hard-coded function name in the library API then it will create issues.

The advantage of the call-back is that in the library API caller does not need to know about the callee function, it only knows the prototypes of the callee function.

Let us see an example code where I am implementing the call-back function using the function pointer.

#include<stdio.h>

//Create a type using typedef
typedef int (*pfCallback)(int,int);


/* API to perform arithmetic operation */
int arithmatic_operation(pfCallback pfun,int data1, int data2)
{
    int ret = 0;

    //calling the callback function pfun
    ret = (*pfun)(data1,data2);
    return ret;
}

//Function perform addition
int addition(int data1, int data2)
{
    return (data1 + data2);
}

//Function perform subtraction
int subtraction(int data1, int data2)
{
    return (data1 - data2);
}


int main(void)
{
    int ret =0;
    //function pointer
    pfCallback ptr_call_back = NULL;

    //Assigned the address of the call back function
    ptr_call_back = addition;

    //Passed function pointer in function
    ret = arithmatic_operation(ptr_call_back, 5, 4);

    printf("Addition of two numbers = %d\n",ret);

    //Assigned the address of the call back function
    ptr_call_back = subtraction;

    //Passed function pointer in function
    ret = arithmatic_operation(ptr_call_back, 5, 4);

    printf("Subtraction of two numbers = %d\n",ret);

    return 0;
}

Output: 

Addition of two numbers = 9
Subtraction of two numbers = 1

 

If you want to learn more about the c language, here 10 Free days (up to 200 minutes) C video course for you.

C tutorial

 

Access the methods from the DLL:

If you are using DLL in your application( windows), then you have to use the function pointer. I have already written an article on how to create a DLL using the visual studio. If you want you can see this article, Create DLL using the visual studio.

Let’s see an example where I am assuming “mathlibrary.dll” is a DLL that has many functions to perform the mathematical operation like addition, subtraction…etc. If we require any one of the function, then we must create a function pointer which has the same prototype of the calling function.

#include <iostream>
#include <windows.h>

//Declaration of function pointer
typedef int (*pfArithmatic)(int,int);


int main(int argc, char** argv)
{

    //Create function pointer
    pfArithmatic addition =NULL;

    int ret  = 0;

    //Load the dll and keep the handle to it
    HINSTANCE hInstLibrary = LoadLibrary("mathlibrary.dll");

    //If the handle is valid, try to get the function address.
    if (hInstLibrary)
    {
        //Get the address of methods
        addition = (pfArithmatic)GetProcAddress(hInstLibrary, "addition");

        //If the function address is valid, call the function.
        if (addition)
        {
            //Now call the methods
            ret = addition(6, 27);

            std::cout << "6 + 27 = " << ret << std::endl;

        }
        //Free the library:
        FreeLibrary(hInstLibrary);

    }
    else
    {
        std::cout << "DLL loading failed!" << std::endl;
    }

    return 0;

}

 

Replace a nested switch using the array of a function pointer:

With the help of array and function pointers, we can replace the nested switch case. Let’s understand it with below the example is shown below., In this code, I have a nested switch case, and I will remove the nested switch case using the array of the function pointer.

In this code, every state has three sub-states and each sub-states has a function to perform the specific task. If you want to execute the function, you need to select the state and substate. For example, if you will select the state Arithmetic and sub-state substate1 than addition will be performed.

Similar to that if you want to display the result of the mathematical operation then you need to select state Message and sub-state substate1.

So let see the code,

#include <stdint.h>
#include <stdio.h>


int arithmetic_result = 0;

//Menu state
typedef enum
{
    Arithmatic = 0,
    Message,
    Laststate
} States;


//Substates
typedef enum
{
    SubState1 = 0,
    SubState2,
    SubState3,
    LastSubState
} SubStates;



/*Functions which are called from nested switch statement.*/
void addition(int data1,int data2)
{
    arithmetic_result = data1 + data2;
}

void subtraction(int data1,int data2)
{
    arithmetic_result = data1 - data2;
}

void multiplication(int data1,int data2)
{
    arithmetic_result = data1 * data2;
}

void addition_message(const char *pcMessage)
{
    printf("%s = %d\n",pcMessage,arithmetic_result);
}

void subtraction_message(const char *pcMessage)
{
    printf("%s = %d\n",pcMessage,arithmetic_result);
}

void multiplication_message(const char *pcMessage)
{
    printf("%s = %d\n",pcMessage,arithmetic_result);
}


/*Function which selects transaction and processing
method on the basis of Menustate and substate */
void arithmetic_operation(States primary_state, SubStates secondary_state)
{
    switch (primary_state)
    {
    case Arithmatic:

        switch (secondary_state)
        {
        case SubState1:
            addition(10,2);
            break;

        case SubState2:
            subtraction(10,2);
            break;
        case SubState3:
            multiplication(10,2);
            break;

        default:
            break;
        }
        break;

    case Message:
        switch (secondary_state)
        {
        case SubState1:
            addition_message("Addition of two numbers");
            break;

        case SubState2:
            subtraction_message("Subtraction of two number");
            break;
        case SubState3:
            multiplication_message("Multiplication of two number");
            break;

        default:
            break;
        }
        break;
    default:
        break;
    }
}


int main(void)
{
    // Arithmatic operation
    arithmetic_operation (Arithmatic, SubState1);

    //Display result of mathmetic operation
    arithmetic_operation (Message, SubState1);

    return 0;
}

Output: Addition of two numbers = 12

 

Now you can see how we can replace the nested switch case with the help of 2D-array and function pointers. You can also see the article, Brief introduction of the array.

#include <stdint.h>
#include <stdio.h>

//used to store result
int arithmatic_result = 0;

//used to store data1
int data1 = 5;

//used to store data2
int data2 = 4;

//Menu state
typedef enum
{
    Arithmatic = 0,
    Message,
    Laststate
} States;


//Substates
typedef enum
{

    SubState1 = 0,
    SubState2,
    SubState3,
    LastSubState
} SubStates;

/*Functions which are called from nested switch statement.*/
void addition(void)
{
    arithmatic_result = data1 + data2;
}

void subtraction(void)
{
    arithmatic_result = data1 - data2;
}

void multiplication(void)
{
    arithmatic_result = data1 * data2;
}

void addition_message(void)
{
    printf("%s = %d\n","Addition",arithmatic_result);
}

void subtraction_message(void)
{
    printf("%s = %d\n","subtraction",arithmatic_result);
}

void multiplication_message(void)
{
    printf("%s = %d\n","multiplication",arithmatic_result);
}


//Create typedef of pointer to function 2D array
typedef void (*const afEventHandler[Laststate][LastSubState])(void);


//2D array of function pointer
void arithmatic_operation(States primary_state, SubStates secondary_state)
{
    static afEventHandler  aArithmaticFunction=
    {
        [Arithmatic] = {[SubState1]= addition,[SubState2]= subtraction, [SubState3]= multiplication},
        [Message] ={[SubState1]= addition_message,[SubState2]= subtraction_message, [SubState3]= multiplication_message},
    };

    if(aArithmaticFunction[primary_state][secondary_state] != NULL) //Check NULL pointer
    {
        (*aArithmaticFunction[primary_state][secondary_state])();
    }
}


int main(void)
{
    // Arithmetic operation
    arithmatic_operation (Arithmatic, SubState1);

    //Display result of mathmetic operation
    arithmatic_operation (Message, SubState1);

    return 0;
}

Output: Addition of two numbers = 9

 

Function pointer in MCU Boot-loader

We can jump from one application to another using the function pointer. I have worked on a project, where we were required to upgrade the firmware of the device from the Wi-Fi.

In this project, we have created a bootloader to upgrade the firmware of the device. In bootloader, we have verified the CRC of the firmware, if CRC is intact, the control jumps from the bootloader to the application using the function pointer.

Let’s see example code on how to jump from bootloader to the application using the function pointer.

//Declare a function pointer for the application
typedef (void)(*pfJumpToApplication)(void);


//Assumed,starting address of the application
#define APPLICATION_STARTING_ADDRESS   (uint32_t)0x08020000



static void JumpToStm32Application(void)
{
    //Create function pointer for the user application
    pfJumpToApplication JumpToAppFun = NULL;
    uint32_t *pApplicationAddress=(uint32_t *)APPLICATION_STARTING_ADDRESS;

    //Disabling the interrupts, before changing interrupt vectors
    __disable_irq();

    //Set vector table offset
    SCB->VTOR = (uint32_t *)pApplicationAddress;

    //Initialize the user application's Stack Pointer
    __set_MSP(APPLICATION_STARTING_ADDRESS);

    //Address for the user Application

    JumpToAppFun = (pfJumpToApplication)(APPLICATION_STARTING_ADDRESS +4);

    //Jump to device application
    JumpToAppFun();
}

 


Polymorphism with the function pointer

Using the function pointer, we can create an illusion of polymorphism. This concept is useful where we need to runtime polymorphism. To accomplish this task we need to create a function pointer within the structure and initialize the function pointer with the corresponding function.

For more detail, you see below articles,

Suppose there is a structure in c that contains function pointers, this function pointer stores the address of the function that calculates the salary of an employee (Grad1 and Grad2 officer).

//structure contains function pointer
typedef struct
{
    int (*BasicCalculation)(void);

    int (*HouseRentCalculation)(void);

    int (*BonusCalculation)(void);

    int (*MedicalCalculation)(void);

    int TotalSallary;

} sSallaryCalculation;


//initialize the structure variables to calculate the salary of Grade_1 officer

sSallaryCalculation *ComposeSalaryGrade_1(void)
{
    sSallaryCalculation *psSalaryCalculate = malloc (sizeof (sSallaryCalculation));

    if (psSalaryCalculate != NULL)
    {

        psSalaryCalculate->BasicCalculation = &Basic_Grade_1;
        psSalaryCalculate->HouseRentCalculation = &HouseRent_Grade_1;
        psSalaryCalculate->BonusCalculation = &Bonus_Grade_1;
        psSalaryCalculate->MedicalCalculation = &Medical_Grade_1;

    }

    return psSalaryCalculate;
}



//initialize the structure variables to calculate the salary of Grade_2 officer

sSallaryCalculation *ComposeSalaryGrade_2(void)
{
    sSallaryCalculation *psSalaryCalculate = malloc (sizeof (sSallaryCalculation));

    if (psSalaryCalculate != NULL)
    {

        psSalaryCalculate->BasicCalculation = &Basic_Grade_2;
        psSalaryCalculate->HouseRentCalculation = &HouseRent_Grade_2;
        psSalaryCalculate->BonusCalculation = &Bonus_Grade_2;
        psSalaryCalculate->MedicalCalculation = &Medical_Grade_2;

    }

    return psSalaryCalculate;
}

//Function to select sallary calculation for Grad1 and Grad2 officer
void CalculateSalary(int ichoice)
{
    sSallaryCalculation *psSalaryCalculate = NULL;

    if(GRADE_1_OFFICER == ichoice)
    {
        //Get the address of callbacks to calculate salary of Grad1 officer
        psSalaryCalculate = ComposeSalaryGrade_1();
    }
    else
    {
        //Get the address of callbacks to calculate salary of Grad2 officer
        psSalaryCalculate = ComposeSalaryGrade_2();

    }

    //Basic salary calculation as per the selection
    psSalaryCalculate->BasicCalculation();

    //House Rent calculation as per the selection
    psSalaryCalculate->HouseRentCalculation();

    //Bonus calculation as per the selection
    psSalaryCalculate->BonusCalculation();

    //Medical calculation as per the selection
    psSalaryCalculate->MedicalCalculation();

    //Get total calculated salary
    psSalaryCalculate->TotalSallary = iTotalCalculateSalary;
}

 

 

 

state machine implementation in C

With the help of array and function pointers, we can implement a state machine in C.  The function pointer store the address of the function which will be invoked at defined state and events.

A finite state machine is one of the popular design patterns, it has multiple states. Its state can be changed by an internal or external input. An input could be signal, hardware or software interrupt, timer expiry…etc. In the finite state machine, the procedure to change one state to another state is called transition. You can see the article, How to implement state machine in C?

 

Recommended Articles for you,



3 comments

Leave a Reply

Your email address will not be published. Required fields are marked *