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.
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,
- How to pass an array as a parameter in C?
- How to access a two-dimensional array using pointers in C?
- Brief Introduction of switch case in C.
- A brief description of the pointer in C.
- Dangling, Void, Null and Wild Pointers
- How to use function pointer in C?
- How to use the structure of function pointer in c language?
- Replace the nested switch case using an array and function pointer.
- Implement state machine in C.
- Function pointer in structure.
- Pointer Arithmetic in C.
- void pointer in C.
- 10 questions about dynamic memory allocation.
- Memory Layout in C.
- 100 C interview Questions
- File handling in C.
- C format specifiers.