Afunction pointer, also called asubroutine pointer orprocedure pointer, is apointer referencing executable code, rather than data.Dereferencing the function pointer yields the referencedfunction, which can be invoked and passed arguments just as in a normal function call. Such an invocation is also known as an "indirect" call, because the function is being invokedindirectly through a variable instead ofdirectly through a fixed identifier or address.
Function pointers allow different code to be executed at runtime. They can also be passed to a function to enablecallbacks.
Function pointers are supported bythird-generationprogramming languages (such asPL/I,COBOL,Fortran,[1]dBASE dBL[clarification needed], andC) andobject-oriented programming languages (such asC++,C#, andD).[2]
The simplest implementation of a function (or subroutine) pointer is as avariable containing theaddress of the function within executable memory. Olderthird-generation languages such asPL/I andCOBOL, as well as more modern languages such asPascal andC generally implement function pointers in this manner.[3]
Function pointers were introduced inC# version 9.0, asdelegate*.[4]
The following C program illustrates the use of two function pointers:
func1 takes one double-precision (double) parameter and returns another double, and is assigned to a function which converts centimeters to inches.func2 takes a pointer to a constant character array as well as an integer and returns a pointer to a character, and is assigned to aC string handling function which returns a pointer to the first occurrence of a given character in a character array.#include<stdio.h>#include<string.h>doublecm_to_inches(doublecm){returncm/2.54;}// "strchr" is part of the C string handling (i.e., no need for declaration)// See https://en.wikipedia.org/wiki/C_string_handling#Functionsintmain(void){double(*func1)(double)=cm_to_inches;char*(*func2)(constchar*,int)=strchr;printf("%f %s",func1(15.0),func2("Wikipedia",'p'));// prints "5.905512 pedia"return0;}
The next program uses a function pointer to invoke one of two functions (sin orcos) indirectly from another function (compute_sum, computing an approximation of the function'sRiemann integration). The program operates by having functionmain call functioncompute_sum twice, passing it a pointer to the library functionsin the first time, and a pointer to functioncos the second time. Functioncompute_sum in turn invokes one of the two functions indirectly by dereferencing its function pointer argumentfuncp multiple times, adding together the values that the invoked function returns and returning the resulting sum. The two sums are written to the standard output bymain.
#include<math.h>#include<stdio.h>// Function taking a function pointer as an argumentdoublecompute_sum(double(*funcp)(double),doublelo,doublehi){doublesum=0.0;// Add values returned by the pointed-to function '*funcp'for(inti=0;i<=100;i++){// Use the function pointer 'funcp' to invoke the functiondoublex=i/100.0*(hi-lo)+lo;doubley=funcp(x);sum+=y;}returnsum/101.0*(hi-lo);}doublesquare(doublex){returnx*x;}intmain(void){doublesum;// Use standard library function 'sin()' as the pointed-to functionsum=compute_sum(sin,0.0,1.0);printf("sum(sin): %g\n",sum);// Use standard library function 'cos()' as the pointed-to functionsum=compute_sum(cos,0.0,1.0);printf("sum(cos): %g\n",sum);// Use user-defined function 'square()' as the pointed-to functionsum=compute_sum(square,0.0,1.0);printf("sum(square): %g\n",sum);return0;}
Functors, or function objects, are similar to function pointers, and can be used in similar ways. A functor is an object of a class type that implements thefunction-call operator, allowing the object to be used within expressions using the same syntax as a function call. Functors are more powerful than simple function pointers, being able to contain their own data values, and allowing the programmer to emulateclosures. They are also used as callback functions if it is necessary to use a member function as a callback function.[5]
Many "pure" object-oriented languages do not support function pointers. Something similar can be implemented in these kinds of languages, though, usingreferences tointerfaces that define a singlemethod (member function).CLI languages such asC# andVisual Basic .NET implementtype-safe function pointers withdelegates.
In other languages that supportfirst-class functions, functions are regarded as data, and can be passed, returned, and created dynamically directly by other functions, eliminating the need for function pointers.
Extensively using function pointers to call functions may produce a slow-down for the code on modern processors, because abranch predictor may not be able to figure out where to branch to (it depends on the value of the function pointer at run time) although this effect can be overstated as it is often amply compensated for by significantly reduced non-indexed table lookups.
C++ includes support forobject-oriented programming, so classes can havemethods (usually referred to as member functions). Non-static member functions (instance methods) have an implicit parameter (thethis pointer) which is the pointer to the object it is operating on, so the type of the object must be included as part of the type of the function pointer. The method is then used on an object of that class by using one of the "pointer-to-member" operators:.* or->* (for an object or a pointer to object, respectively).[dubious –discuss]
Although function pointers in C and C++ can be implemented as simple addresses, so that typicallysizeof(Fx) == sizeof(void*), member pointers in C++ are sometimes implemented as "fat pointers", typically two or three times the size of a simple function pointer, in order to deal withvirtual methods andvirtual inheritance[citation needed].
In C++, in addition to the method used in C, it is also possible to use theC++ standard library class templatestd::function, of which the instances are function objects:
importstd;staticdoublederivative(conststd::function<double(double)>&f,doublex0,doubleeps){doubleeps2=eps/2;doublelo=x0-eps2;doublehi=x0+eps2;return(f(hi)-f(lo))/eps;}staticdoublef(doublex){returnx*x;}intmain(){doublex=1;std::println("d/dx(x ^ 2) [@ x = {}] = {}",x,derivative(f,x,1e-5));return0;}
This is how C++ uses function pointers when dealing with member functions of classes or structs. These are invoked using an object pointer or a this call. They are type safe in that you can only call members of that class (or derivatives) using a pointer of that type. This example also demonstrates the use of a typedef for the pointer to member function added for simplicity. Function pointers to static member functions are done in the traditional 'C' style because there is no object pointer for this call required.
importstd;classFoo{public:[[nodiscard]]staticintadd(inti,intj)noexcept{returni+j;}[[nodiscard]]staticintmult(inti,intj)noexcept{returni*j;}[[nodiscard]]staticintnegate(inti)noexcept{return-i;}};intbar1(inti,intj,Foo*pFoo,int(Foo::*pfn)(int,int)){return(pFoo->*pfn)(i,j);}typedefint(Foo::*Foo_pfn)(int,int);intbar2(inti,intj,Foo*pFoo,Foo_pfnpfn){return(pFoo->*pfn)(i,j);}typedefauto(*PFN)(int)->int;// C++ only, same as: typedef int(*PFN)(int);intbar3(inti,PFNpfn){returnpfn(i);}intmain(){Foofoo;std::println("Foo::add(2,4) = {}",bar1(2,4,&foo,&Foo::add));std::println("Foo::mult(3,5) = {}",bar2(3,5,&foo,&Foo::mult));std::println("Foo::negate(6) = {}",bar3(6,&Foo::negate));return0;}
The C andC++ syntax given above is the canonical one used in all the textbooks - but it's difficult to read and explain. Even the abovetypedef examples use this syntax. However, every C and C++ compiler supports a more clear and concise mechanism to declare function pointers: usetypedef, butdon't store the pointer as part of the definition. Note that the only way this kind oftypedef can actually be used is with a pointer - but that highlights the pointer-ness of it.
// This declares 'F', a function that accepts a 'char' and returns an 'int'. Definition is elsewhere.intF(charc);// This defines 'Fn', a type of function that accepts a 'char' and returns an 'int'.typedefintFn(charc);// This defines 'fn', a variable of type pointer-to-'Fn', and assigns the address of 'F' to it.Fn*fn=&F;// Note '&' not required - but it highlights what is being done.// This calls 'F' using 'fn', assigning the result to the variable 'a'inta=fn('A');// This defines 'Call', a function that accepts a pointer-to-'Fn', calls it, and returns the resultintCall(Fn*fn,charc){returnfn(c);}// Call(fn, c)// This calls function 'Call', passing in 'F' and assigning the result to 'call'intcall=Call(&F,'A');// Again, '&' is not required// LEGACY: Note that to maintain existing code bases, the above definition style can still be used first;// then the original type can be defined in terms of it using the new style.// This defines 'PFn', a type of pointer-to-type-Fn.typedefFn*PFn;// 'PFn' can be used wherever 'Fn *' canPFnpfn=F;intCallP(PFnfn,charc);
These examples use the above definitions. In particular, note that the above definition forFn can be used in pointer-to-member-function definitions:
// This defines 'C', a class with similar static and member functions,// and then creates an instance called 'c'classC{public:staticintStatic(charc);intMember(charc);}c;// C// This defines 'p', a pointer to 'C' and assigns the address of 'c' to itC*p=&c;// This assigns a pointer-to-'Static' to 'fn'.// Since there is no 'this', 'Fn' is the correct type; and 'fn' can be used as above.fn=&C::Static;// This defines 'm', a pointer-to-member-of-'C' with type 'Fn',// and assigns the address of 'C::Member' to it.// You can read it right-to-left like all pointers:// "'m' is a pointer to member of class 'C' of type 'Fn'"FnC::*m=&C::Member;// This uses 'm' to call 'Member' in 'c', assigning the result to 'cA'intcA=(c.*m)('A');// This uses 'm' to call 'Member' in 'p', assigning the result to 'pA'intpA=(p->*m)('A');// This defines 'Ref', a function that accepts a reference-to-'C',// a pointer-to-member-of-'C' of type 'Fn', and a 'char',// calls the function and returns the resultintRef(C&r,FnC::*m,charc){return(r.*m)(c);}// Ref(r, m, c)// This defines 'Ptr', a function that accepts a pointer-to-'C',// a pointer-to-member-of-'C' of type 'Fn', and a 'char',// calls the function and returns the resultintPtr(C*p,FnC::*m,charc){return(p->*m)(c);}// Ptr(p, m, c)// LEGACY: Note that to maintain existing code bases, the above definition style can still be used first;// then the original type can be defined in terms of it using the new style.// This defines 'FnC', a type of pointer-to-member-of-class-'C' of type 'Fn'typedefFnC::*FnC;// 'FnC' can be used wherever 'Fn C::*' canFnCfnC=&C::Member;intRefP(C&p,FnCm,charc);
PL/I procedures can be nested, that is, procedure A may contain procedure B, which in turn may contain C. In addition to data declared in B, B can also reference any data declared in A, as long as it doesn’t override the definition. Likewise C can reference data in both A and B. Therefore, PL/I ENTRY variables need to containcontext,[6] to provide procedure C with the addresses of the values of data in B and A at the time C was called.
Function Pointers are pointers, i.e. variables, which point to the address of a function
Important note: A function pointer always points to a function with a specific signature! Thus all functions, you want to use with the same function pointer, must have the same parameters and return-type!
If you want to use a member function as a callback function, then the member function needs to be associated with an object of the class before it can be called. In this case, you can use functor [with an example on this page].