Function pointer

Last updated

A function pointer, also called a subroutine pointer or procedure pointer, is a 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.

Contents

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-generation programming languages (such as PL/I, COBOL, Fortran, [1] dBASE dBL, and C) and object-oriented programming languages (such as C++, C#, and D). [2]

Simple function pointers

The simplest implementation of a function (or subroutine) pointer is as a 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. [3]

Example in C

The following C program illustrates the use of two function pointers:

#include<stdio.h>  /* for printf */#include<string.h> /* for strchr */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 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.

#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'inti;for(i=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

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 the 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. [4]

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).[ dubious ]

Although function pointers in C and C++ can be implemented as simple addresses, so that typically sizeof(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 with virtual methods and virtual inheritance [ citation needed ].

In C++

In C++, in addition to the method used in C, it is also possible to use the C++ standard library class template std::function, of which the instances are function objects:

#include<iostream>#include<functional>usingnamespacestd;staticdoublederivative(constfunction<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;cout<<"d/dx(x ^ 2) [@ x = "<<x<<"] = "<<derivative(f,x,1e-5)<<endl;return0;}

Pointers to member functions in C++

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.

#include<iostream>usingnamespacestd;classFoo{public:intadd(inti,intj){returni+j;}intmult(inti,intj){returni*j;}staticintnegate(inti){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;cout<<"Foo::add(2,4) = "<<bar1(2,4,&foo,&Foo::add)<<endl;cout<<"Foo::mult(3,5) = "<<bar2(3,5,&foo,&Foo::mult)<<endl;cout<<"Foo::negate(6) = "<<bar3(6,&Foo::negate)<<endl;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++

// 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);

C++

These examples use the above definitions. In particular, note that the above definition for Fn 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);

See also

Related Research Articles

C is a general-purpose computer programming language. It was created in the 1970s by Dennis Ritchie, and remains very widely used and influential. By design, C's features cleanly reflect the capabilities of the targeted CPUs. It has found lasting use in operating systems, device drivers, and protocol stacks, but its use in application software has been decreasing. C is commonly used on computer architectures that range from the largest supercomputers to the smallest microcontrollers and embedded systems.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In mathematics and computer science, a higher-order function (HOF) is a function that does at least one of the following:

In computer science, a type signature or type annotation defines the inputs and outputs of a function, subroutine or method. A type signature includes the number, types, and order of the function's arguments. One important use of a type signature is for function overload resolution, where one particular definition of a function to be called is selected among many overloaded forms.

<span class="mw-page-title-main">C syntax</span> Set of rules defining correctly structured programs

The syntax of the C programming language is the set of rules governing writing of software in C. It is designed to allow for programs that are extremely terse, have a close relationship with the resulting object code, and yet provide relatively high-level data abstraction. C was the first widely successful high-level language for portable operating-system development.

<span class="mw-page-title-main">Pointer (computer programming)</span> Object which stores memory addresses in a computer program

In computer science, a pointer is an object in many programming languages that stores a memory address. This can be that of another value located in computer memory, or in some cases, that of memory-mapped computer hardware. A pointer references a location in memory, and obtaining the value stored at that location is known as dereferencing the pointer. As an analogy, a page number in a book's index could be considered a pointer to the corresponding page; dereferencing such a pointer would be done by flipping to the page with the given page number and reading the text found on that page. The actual format and content of a pointer variable is dependent on the underlying computer architecture.

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. In some languages, particularly C++, function objects are often called functors.

In computer programming, a callback is a function that is stored as data and designed to be called by another function – often back to the original abstraction layer.

In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The definition of a reference in C++ is such that it does not need to exist. It can be implemented as a new name for an existing object.

In mathematics and in computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.

In some programming languages, const is a type qualifier, which indicates that the data is read-only. While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in that it is part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking. In other languages, the data is not in a single memory location, but copied at compile time for each use. Languages which use it include C, C++, D, JavaScript, Julia, and Rust.

typedef is a reserved keyword in the programming languages C, C++, and Objective-C. It is used to create an additional name (alias) for another data type, but does not create a new type, except in the obscure case of a qualified typedef of an array type where the typedef qualifiers are transferred to the array element type. As such, it is often used to simplify the syntax of declaring complex data structures consisting of struct and union types, although it is also commonly used to provide specific descriptive type names for integer data types of varying sizes.

In computer programming, the term hooking covers a range of techniques used to alter or augment the behaviour of an operating system, of applications, or of other software components by intercepting function calls or messages or events passed between software components. Code that handles such intercepted function calls, events or messages is called a hook.

sizeof is a unary operator in the programming languages C and C++. It generates the storage size of an expression or a data type, measured in the number of char-sized units. Consequently, the construct sizeof (char) is guaranteed to be 1. The actual number of bits of type char is specified by the preprocessor macro CHAR_BIT, defined in the standard include file limits.h. On most modern computing platforms this is eight bits. The result of sizeof has an unsigned integer type that is usually denoted by size_t.

The C and C++ programming languages are closely related but have many significant differences. C++ began as a fork of an early, pre-standardized C, and was designed to be mostly source-and-link compatible with C compilers of the time. Due to this, development tools for the two languages are often integrated into a single product, with the programmer able to specify C or C++ as their source language.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

Substitution failure is not an error (SFINAE) is a principle in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.

C++ doesn't have:

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

References

  1. Andrew J. Miller. "Fortran Examples" . Retrieved 2013-09-14.
  2. "The Function Pointer Tutorials". logo. Archived from the original on 2011-05-16. Retrieved 2011-04-13. Function Pointers are pointers, i.e. variables, which point to the address of a function
  3. "The Function Pointer Tutorials". logo. Archived from the original on 2011-05-16. Retrieved 2011-04-13. 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!
  4. "Expertise: Intermediate Language: C++: Use Functor for Callbacks in C++". DevX.com. 2005-01-31. Retrieved 2011-04-13. 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].