Article de reference

Function pointer

A function pointer , also called a subroutine pointer or procedure pointer , is a pointer referencing executable code, rather than data. Dereferencing the function pointer yield...

pointer referencing executable code, rather than data. Dereferencing the function pointer yields the referenced function, 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 invoked indirectly through a variable instead of directly 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 enable callbacks.

Function pointers are supported by third-generationprogramming languages (such as PL/I, COBOL, Fortran,dBASE dBLC) and object-oriented programming languages (such as C++, C#, and D).

variable containing the address of the function within executable memory. Older third-generation languages such as PL/I and COBOL, as well as more modern languages such as Pascal and C generally implement function pointers in this manner.

Function pointers were introduced in C# version 9.0, as delegate*.

Example in C

C string handling function which returns a pointer to the first occurrence of a given character in a character array.
// 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 or cos) indirectly from another function (compute_sum, computing an approximation of the function's Riemann integration). The program operates by having function main call function compute_sum twice, passing it a pointer to the library function sin the first time, and a pointer to function cos the second time. Function compute_sum in turn invokes one of the two functions indirectly by dereferencing its function pointer argument funcp 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 by main.

",sum);// Use standard library function 'cos()' as the pointed-to functionsum=compute_sum(cos,0.0,1.0);printf("sum(cos): %g",sum);// Use user-defined function 'square()' as the pointed-to functionsum=compute_sum(square,0.0,1.0);printf("sum(square): %g",sum);return0;}

Functors

function-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 emulate closures. They are also used as callback functions if it is necessary to use a member function as a callback function.

Many "pure" object-oriented languages do not support function pointers. Something similar can be implemented in these kinds of languages, though, using references to interfaces that define a single method (member function). CLI languages such as C# and Visual Basic .NET implement type-safe function pointers with delegates.

In other languages that support first-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 a branch 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.

Method pointers

C++ includes support for object-oriented programming, so classes can have methods (usually referred to as member functions). Non-static member functions (instance methods) have an implicit parameter (the this 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).fat pointers", typically two or three times the size of a simple function pointer, in order to deal with virtual methods and virtual inheritance.C++ standard library class template std::function, of which the instances are function objects:

,x,derivative(f,x,1e-5));return0;}

Pointers to member functions in C++

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.

*pfn)(i,j); } typedef int(Foo::*Foo_pfn)(int,int); int bar2(int i, int j, Foo* pFoo, Foo_pfn pfn) { return (pFoo->*pfn)(i,j); } typedef auto(*PFN)(int) -> int; // C++ only, same as: typedef int(*PFN)(int); int bar3(int i, PFN pfn) { return pfn(i); } int main() { Foo foo; 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)); return 0; } "
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;}

Alternate C and C++ syntax

The C and C++ syntax given above is the canonical one used in all the textbooks - but it's difficult to read and explain. Even the above typedef examples use this syntax. However, every C and C++ compiler supports a more clear and concise mechanism to declare function pointers: use typedef, but don't store the pointer as part of the definition. Note that the only way this kind of typedef can actually be used is with a pointer - but that highlights the pointer-ness of it.

C and C++

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

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 contain context, to provide procedure C with the addresses of the values of data in B and A at the time C was called.