3.4 Function Pointers
Function pointers are just like regular pointers, but can point to functions. Recall, functions in your code are stored in code segment of the memory (refer to link). Any thing stored in memory could be pointed by a pointer. Therefore, pointers that can point functions stored in the memory called function pointers.
Once a function pointer is declared to point to a function that carries a particular function signature (return type, parameter types), the function pointer is locked to that type and will not be able to point to functions that carry a different signature.
void func(int iNum1, int iNum2){ printf("func %d, %d\n", iNum1, iNum2);}
/* The function signature (or prototype) * of the function defined above is: * This is also called the shorthand "function declaration" */void func(int, int);
/* Note that the parameter names are optional for the * compiler as long as it knows how many bits to allocate * for each parameter via the type of the parameter. */
1. Declaring a function pointer
Lets compare similarity between regular pointer declaration vs function pointer declaration.
Pointers typically involve 3 steps:
- Declaration of the pointer
- Initialization of the pointer
- Dereference of the pointer
int num = 10;int* piPtr; /* Step 01: Declaration of the pointer */piPtr = # /* Step 02: Initialization of the pointer */*piPtr = 100; /* Step 03: Dereferencing of a pointer */
void func(int iNum1, int iNum2){ printf("func %d, %d\n", iNum1, iNum2);}
void func3(int iNum1, int iNum2, int iNum3){ printf("func3 %d, %d, %d\n", iNum1, iNum2, iNum3);}
/* Assume, a function pointer to point * the function 'func' needs to be defined */
/* Step 01: Declaration of the function pointer *//* ----------------------------------------------- */
/* Take the function signature for 'func' defined above *//* void func(int, int) * Refer below for the next step */
void (*fptr )( int , int );/* In the statement above, the enclosing brackets of *fptr * i.e. ( *fptr ) * and the parameter brackets * i.e. ( int, int ) * denote it’s a function pointer but not a regular pointer */
/* Step 02: Initialization of the function pointer *//* ----------------------------------------------- */fptr = &func;
/* L-Value type: void (*)(int, int) * R-Value type: void (*)(int, int) * Therefore, the initialization is valid */
/* Is the following assignment valid ? */fptr = &func3; /* NO */
/* L-Value type: void (*)(int, int) * R-Value type: void (*)(int, int, int) * type mismatch, the assignment is NOT valid */
/* Step 03: Dereferencing of a function pointer *//* ----------------------------------------------- *//* In the context of a function pointer, dereferencing * means, goto that the location where the function definition * is stored in the memory, invoke it with arguments passed */
(*fptr)(5 , 10); /* invoking the function pointed by fptr with the params 5, 10 *//* Once again, the brackets ( *fptr ) ( 5,10 ) denotes * it is a function pointer derefence but * not a regular pointer derefence */
2. How to typedef
a Function Pointer Type?
typedef is used to define a new type out of an existing type or define a complex type like function pointer type or c-struct type.
typedef int UCP_int; /* deriving UCP_int from int */UCP_int iNum = 10; /* same as below, since UCP_int is essentially an int */int iNum2 = 10;
typedef unsigned long int size_t; /* available by default via stddef.h */size_t uliNum1 = 100;unsinged long int uliNum2 = 100;
typedef long int ptrdiff_t; /* available by default via stddef.h */ptrdiff_t liNum1 = -100;long int liNum2 = -100;
Now lets look at how to typedef
a Function Pointer Type
/* Recall the program shown above (Ref: Declaring a function pointer) */void (*fptr)(int, int); /* fptr is a function pointer, but not a function pointer type */fptr = &func;(*fptr)(5, 10);
/* ------------- TYPEDEF -------------------------------------- *//* The type of fptr is void (*)(int, int) *//* Typically, you would think the typedef should be */typedef void (*)(int, int) FptrType;/* But, the compiler does not like (*) a floating star operator * without a operand (identifier name) or something next to it. * Therefore, the statement above is NOT allowed. */
/* The right way to do it */typedef void (*FptrType)(int, int);/* Move the type name (i.e. FptrType) inside the brackets (*...) next to the star */
/* Now you can use the new type FptrType to declare a variable (function pointer) * of the type void (*)(int, int) as defined by FptrType */ FptrType fptr; fptr = &func; (*fptr)(5, 10);
/* fptr is a function pointer, but not a function pointer type */ /* FptrType is the type of the function pointer fptr */
3. How Do You Return a Function Pointer?
typedef void (*FptrType)(int, int);
void dummy(int iNum1, int iNum2){ printf("dummy: %d, %d\n", iNum1, iNum2);}
/* Following is a function that returns a function pointer *//* Hence the return type is a function pointer type * which defined above as FptrType */FptrType fetchFuncPointerToDummy(){ return &dummy; /* type of &dummy is: void (*)(int, int) */ /* Hence it is typedef-ed as FptrType */}
int main(){ FptrType fptr; fptr = fetchFuncPointerToDummy() (*fptr) (10, 20);}
typedef int (*FptrType)();
int random(){ printf("random()\n");}
FptrType getRandomFunc(){ return &random;}
int main(){ FptrType fptr = getRandomFunc(); (*fptr)();}
4. Why typedef
are Always Placed in Header Files?
You should always place typedefs in the header file if the header file lists the function that uses the type.
#ifndef UTIL_H#define UTIL_H
typedef int (*FptrType)();FptrType getRandomFunc();
/* The function definition (implementation) of getRandomFunc() goes to * util.c and util.c must be aware of the type FptrType to return a value * of that type. * We include util.h in util.c to make util.c aware of the new type FptrType */
/* if util.h is included in main.c, main.c will be able to use * getRandomFunc() and get a value of the type FptrType returned * successfully. Hence main.c must be aware of FptrType to make sense * of the return value of getRandomFunc(). * Note that, with the include of util.h in main.c, the typdef-ed FptrType * will be available for main.c as well. */
#endif
#include "util.h"/* The new typedef-ed type "FptrType" will be available now */
int random(){ printf("random()\n");}
FptrType getRandomFunc(){ return &random;}
#include "util.h"/* The new typedef-ed type "FptrType" will be available now */
int main(){ FptrType fptr = getRandomFunc(); (*fptr)();
return 0;}