What Is the Point of Function Pointers

How do function pointers in C work?

Function pointers in C

Let's start with a basic function which we will be pointing to:

int addInt(int n, int m) {
return n+m;
}

First thing, let's define a pointer to a function which receives 2 ints and returns an int:

int (*functionPtr)(int,int);

Now we can safely point to our function:

functionPtr = &addInt;

Now that we have a pointer to the function, let's use it:

int sum = (*functionPtr)(2, 3); // sum == 5

Passing the pointer to another function is basically the same:

int add2to3(int (*functionPtr)(int, int)) {
return (*functionPtr)(2, 3);
}

We can use function pointers in return values as well (try to keep up, it gets messy):

// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int
int (*functionFactory(int n))(int, int) {
printf("Got parameter %d", n);
int (*functionPtr)(int,int) = &addInt;
return functionPtr;
}

But it's much nicer to use a typedef:

typedef int (*myFuncDef)(int, int);
// note that the typedef name is indeed myFuncDef

myFuncDef functionFactory(int n) {
printf("Got parameter %d", n);
myFuncDef functionPtr = &addInt;
return functionPtr;
}

Where exactly do function pointers point?

Function pointer also point into memory, the only difference is that there is executable code at that memory location instead of data.

On many platforms if you try to execute data (e.g. regular memory) you'll crash or cause an exception. This is known as Data Execution Prevention - a security measure to prevent applications inadvertently running dodgy code that may be placed there by malware.

Why must function pointers be used?

TL; DR

"Function" and "pointer to function" is the same.


There is the concept of a pointer, and the syntax of its usage; it's not clear what you are asking about.

Concept

A pointer to a function may be different from the function itself (the difference is not useful in c++ - see below) in that a function may occupy much space - its code can be arbitrarily complex. Manipulating (e.g. copying or searching/modifying) the code of a function is rarely useful, so c/c++ don't support it at all. If you want to modify the code of a function, cast a pointer to char*, applying all the necessary precautions (I have never done it).

So if you are writing C, all you need is pointers to functions.

However...

Syntax

If you have a pointer p to a function, how do you want to call the function?

(*p)(18); // call the function with parameter 18
p(18); // the same, but looks better!

There is the slightly cleaner syntax not involving the * sign. To support it, the authors of c/c++ invented the concept of "decay" - when your code mentions "a function", the compiler silently "corrects" it to mean "a pointer to a function" instead (in almost all circumstances; excuse me for not detailing further). This is very similar to the "decay" of an array to a pointer mentioned by vsoftco.

So in your example

void runprint(int function(int x), int x) {
cout << function(x) << endl;
}

the "function" type is actually a "pointer to function" type. Indeed, if you try to "overload":

void runprint(int (*function)(int x), int x) {
cout << function(x) << endl;
}

the compiler will complain about two identical functions with identical set of parameters.

Also, when making a variable of a function / pointer-to-function type

runprint(add, 1);

it also doesn't matter:

runprint(&add, 1); // does exactly the same

P.S. When declaring a function that receives a callback, I have mostly seen (and used) the explicitly written pointer. It has only now occurred to me that it's inconsistent to rely on function-to-pointer decay when calling the callback, but not when declaring my code. So if the question is

why does everyone declare callbacks using a pointer-to-function syntax, when a function syntax would be sufficient?

I'd answer "a matter of habit".

Why do function pointers exist as long as they act similar to functions themselves?

Function pointers are necessary when you want a variable to refer to a particular function. For example:

#include <stdio.h>

void foo1(void)
{
printf("foo1\n");
}

void foo2(void)
{
printf("foo2\n");
}

int main()
{
void (*f)(void) = foo1;
f();
f = foo2;
f();
return 0;
}

Output:

foo1
foo2

If you attempted to do this:

void f(void) = foo1;

It would be invalid syntax. And if you removed the initializer:

void f(void);

You would have a function declaration.

What are function pointers used for, and how would I use them?

A simple case is like this: You have an array of operations (functions) according to your business logic. You have a hashing function that reduces an input problem to one of the business logic functions. A clean code would have an array of function pointers, and your program will deduce an index to that array from the input and call it.

Here is a sample code:

typedef void (*fn)(void) FNTYPE;
FNTYPE fn_arr[5];

fn_arr[0] = fun1; // fun1 is previously defined
fn_arr[1] = fun2;
...

void callMyFun(string inp) {
int idx = decideWhichFun(inp); // returns an int between 0 and 4
fn_arr[idx]();
}

But of course, callbacks are the most common usage. Sample code below:

void doLengthyOperation(string inp, void (*callback)(string status)) {
// do the lengthy task
callback("finished");
}

void fnAfterLengthyTask(string status) {
cout << status << endl;
}

int main() {
doLengthyOperation(someinput, fnAfterLengthyTask);
}

What is the purpose of Function Pointer syntax in C?

  1. Function pointer variables are useful when control flow that follows later on modifies the function pointer (e.g. chooses a different callback).

    Function pointer variables are also useful when dealing with runtime binding, where you do not know the function at compile time but rather assign a function pointer at runtime, for example by using dlsym. This is often used in the context of extensible APIs (OpenGL is a popular user of this scheme, for example) and plugins.

  2. "The simplest syntax is that of needsCallback but that isn't done anywhere, it's always needsCallbackPointer and fnPtrAmp. Why?": to have the declaration in the parameter of a function consistent with how an variable or typedef declaration would look like.

  3. Another question you ask is why *fnPtr works, and why the parentheses.

    Well, the parentheses are required, because the function call operator () has a higher precedence than the dereference operator *, thus the function is first called and then the return value is derefenced. (*fnPtr)() works around that.

  4. someFunction and &someFunction are equivalent due to functions not being first-class citizens in C (functions are not normal objects that can be manipulated, like an int, for example), but function pointers are. Thus a function name is always and inherently converted to a function pointer to the function referenced by that name. Note that you can apply & multiple times to a function pointer, yielding a pointer to function pointer, pointer to pointer to function pointer etc.. Thus it does not behave in a sense like * does, which you can use as often as you want on a function pointer.

  5. *fnPtr works, because the * operator used on a function pointer essentially yields the exact same pointer. Same rationale as 4) - there are no function objects in the language. Thus you cannot get a function name back from a function pointer, not possible.

I don't know why the these operators were defined for function names and pointers, respectively. Maybe historic reasons? For consistency with other pointer types?

I suspect that the operator-less syntax was introduced later on to save typing, since you can't use a function name neither in an rvalue nor lvalue context meaningfully. Since theres nothing one can do with a function pointer either (except passing it around. You can of course change it, like fnPtr++; but where does that get you?), it makes quite a lot of sense to add the implicit conversion making fnPtr() possible, to save typing yet again.

(The last two paragraphs are pure speculation on my part.)



Related Topics



Leave a reply



Submit