Function Pointer Type (*)()

This page was translated by a robot.

In C and C++, functions can not only be called by specifying a symbol, but also using a function pointer. Such a function pointer stores the address of the function to be called and its type is a pointer to a function consisting of a return type and a parameter list.









3.141590

3.14
#include <stdio.h>

void printnormal(double f)   {printf("%f\n", f);}
void printformatted(double f){printf("%1.2f\n", f);}

int main(){
  void (*funcptr)(double);
  funcptr = &printnormal;
  (*funcptr)(3.14159);
  funcptr = &printformatted;
  (*funcptr)(3.14159);
  return 0;
}

Details

Using a function pointer, it is possible to assign a pointer to a function to a variable, which can be addressed elsewhere in the program by calling this same variable. Any pointer to a function can be assigned to a function pointer, as long as the function has the same function type as the function pointer expects.

At the point of the call, it is fundamentally unknown which function is stored in the variable. However, the function is called like a normal function call: arguments are passed and the function returns a value. Based on this consideration, a function pointer is also referred to as a handler in certain situations , in the sense that the function (handles) a specific set of arguments. However, what exactly the function executes does not need to be known to the compiler or the programmer.

Programming function pointers is a little confusing, but is explained step-by-step here. Below is also a summary of commonly used function pointer declarations. At the very end, some applications where function pointers can be useful are given.

Function pointer in C

The declaration of a function pointer must be written as follows:

Return-Type (*variable_name)(Parameterlist);

The return type and the parameter list correspond to the prototype of the function that is to be stored in the variable. The parameter list can be specified with or without parameter names, but must always include the types of the parameters. The name of the variable that is declared with the function pointer is *in parentheses with a pointer character appended at the front.

The additional parentheses are to be understood as parentheses of the type expression. These brackets are necessary to tell the compiler that this is a pointer to a function and not a function that returns a pointer. If the brackets were omitted or the pointer character was written outside the brackets, the compiler would regard this line as a normal function declaration.

The assignment to a function pointer can be done in two ways:

variable_name = &global_function_name;
variable_name =  global_function_name;

The first line shows the originally correct variant, in which the address of the function is assigned to the symbol that represents the function pointer using the address operator . The second variant is a simplified notation (so-called Syntactic Sugar ) and does exactly the same thing. This shorthand is usually allowed in today's compilers. For a better understanding, the first variant is always used on this page, as it explicitly refers to addressing.

The function can also be called in two ways:

(*variable_name)(Argumentlist);
  variable_name (Argumentlist);

Again, the first line designates the originally correct variant, with the second line showing a simplified notation. The additional round brackets in the first line are necessary because of the operator precedence: the function call operator has higher precedence than the dereference operator .

Function Pointer as a Return Value

Function pointers can also appear as the return value of a function. To declare a function with the corresponding function pointer type as the return type, the name of the function must be written in parentheses ( )with the pointer character , along with its argument list *.

The following example testdeclares a function that takes an argument xof type intand itself returns a function pointer that points to a function that takes a type as an argument doubleand floatreturns a type:

float (*test(int x))(double);

If the return type points to non-static functions within a namespace, the namespace must also be specified with the range operator:: before the pointer character, as described above.

float (namespace_name:: *test(int x))(double);

Using typedef

The declaration of function pointers is confusing and can easily lead to misinterpretation when looking at the code. However, since function pointers are types, it is possible typedefto save as a symbol using a complicated type expression just like any other type.

In the following example, the symbol is assigned functiontypea function typedefpointer that points to a function that takes a type as an argument doubleand floatreturns a type:

typedef float (*functiontype)(double);

The example from the previous section can be written as follows:

functiontype test(int x);

By using typedefs, the function pointer type can be used just like any other type.

Applications

In C++, function pointers are not commonly used because C++ provides a more convenient (but not necessarily better) way to call functions without explicit knowledge using virtual methods.

However, if, for example, the C++ language is explicitly dispensed with, then mechanisms such as virtual methods must be emulated using C. For example, libraries are often written in C rather than C++. In C such mechanisms can be simulated with conditions ( ifor switch) or by means of function pointers.

In this context it should be noted that the use of function pointers is often faster than the execution of conditions. If, for example, within a loop or a frequently called function due to a condition, the function to be addressed is constantly evaluated using ifor switch, this can take some time. This decision can be made once outside the loop or function using a function pointer, and the resulting function can then be addressed within the loop or function using the function pointer.

The author has found that using function pointers is only slightly more work, but in turn improves speed, typedefeven increases readability with s and can avoid hard-to-find errors in complicated conditions.

The use of function pointers for state machines is still widespread. State machines are programs that have one or more setting parameters that only change when explicitly addressed by the programmer. For each possible setting, the program executes different statements. In order to coordinate the various executions, depending on the setting, other machine-internal functions are called, which can normally be addressed as function pointers. Changing a setting therefore only changes a function pointer, otherwise the machine remains untouched. An example of a state machine is OpenGL.

The idea of ​​the callback function also comes from the area of ​​state machines. For example, a state machine allows the programmer to call a specific function when a certain event occurs. By specifying a function pointer, the programmer can tell the machine which function is to be called in this case.

Furthermore, function pointers are also required for handlers. It is common to program data structures in such a way that the actual content cannot be addressed directly, but only via help functions. This abstracts the actual content and it is not necessary to know the type of programming. Accordingly, some helper functions expect a handler that changes the desired content wherever it is located.

Iterators, for example, run through lists as well as arrays, trees and other structures. Such iterators can often be supplied with a handler which is applied to the current element of the iterator. Function pointers are often used for conversions and often point to relatively small functions.

Ultimately, such constructs also make it possible to apply a function to an entire data structure. Such constructs are often implemented with built-in keywords such as foreach or forall in high-level languages , but these keywords do not exist in C and C++.

Function Pointers and Normal Pointers

Function pointers are handled semantically differently than pointers to data. While a normal pointer points to a memory area that can be freely modified by the programmer, function pointers point to locations in memory where manual access by the user is not permitted.

In principle, the C language allows pointers to void*be cast, including function pointers. Although the compiler allows this, it is strictly forbidden! Code and data have been kept separate in memory for decades. Failure to comply with this separation can lead to unforeseen consequences.

Previously, the memory area containing code was called the text segment and the memory area containing the data was called the data segment . Some systems even define different address sizes depending on whether a pointer points to data or executable code. In this case, a casting would void*possibly even falsify the address.

Some programmers try void*to force function pointers into a different signature by casting to . However, this will most likely lead to a runtime error, since the structure and dismantling of a function must follow an order that is precisely specified by the runtime system . If a function pointer carries an incorrect signature, the program will inevitably run incorrectly and can lead to massively corrupt memory. Fortunately, today's systems have protection mechanisms to protect at least the operating system from such errors.

Since the concept of references does not exist in C, attempts have been made elsewhere to provide at least the most rudimentary protection mechanisms. For example, it is not possible to access the code of a function using the dereference operator . This has a mechanism built in specifically for function pointers so that the return value is the same as the function pointer itself:










Function pointers are equal.
#include <stdio.h>

void printint(int i){
  printf("%d\n", i);
}

int main(){
  void (*functionpointer)(int i) = printint;
  if(functionpointer == *functionpointer){
    printf("Function pointers are equal.\n");
  }
  return 0;
}

However, these special mechanisms only exist to protect against inexperienced programmers. Those in need can breathe easy after this section as they will never get into such situations as they will never try to dereference a function pointer or otherwise convert it to another pointer.

For programmers who still want to address code manually in memory, it is worth taking a look at the function mmap, which is not covered on this page.