Explanation 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;
}

Explanation of function pointers

Well, it is confusing a bit.

Function type and pointer to function type are indeed two different types (no more similar than int and pointer to int). However, there is a rule, that a function type decays to pointer to function type in almost all contexts. Here decaying loosely means converted (there is a difference between type conversion and decaying, but you are probably not interested in it right now).

What is important, is that almost every time you use a function type, you end up with pointer to function type. Note the almost, however - almost every time is not always!

And you are hitting some cases when it doesn't.

typedef void(functionPtr)(int);
functionPtr fun = function;

This code attempts to copy one function (not the pointer! the function!) to another. But of course, this is not possible - you can't copy functions in C++. The compiler doesn't allow this, and I can't believe you got it compiled (you are saying you got linker errors?)

Now, this code:

typedef void(functionPtr)(int);
functionPtr function;
function(5);

function does not shadow anything. Compiler knows it is not a function pointer which can be called, and just calls your original function.

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.

How do function pointers work?

To define a function pointer, use the following syntax:

return_type (*ref_name) (type args, ...)

So, to define a function reference named "doSomething", which returns an int and takes in an int argument, you'd write this:

int (*doSomething)(int number);

You can then assign the reference to an actual function like this:

int someFunction(int argument) {
printf("%i", argument);
}

doSomething = &someFunction;

Once that's done, you can then invoke it directly:

doSomething(5); //prints 5

Because function pointers are essentially just pointers, you can indeed use them as instance variables in your classes.

When accepting function pointers as arguments, I prefer to use a typedef instead of using the cluttered syntax in the function prototype:

typedef int (*FunctionAcceptingAndReturningInt)(int argument);

You can then use this newly defined type as the type of the argument for the function:

void invokeFunction(int func_argument, FunctionAcceptingAndReturningInt func) {
int result = func(func_argument);
printf("%i", result);
}

int timesFive(int arg) {
return arg * 5;
}
invokeFunction(10, ×Five); //prints 50

Explanation of code involving function pointers and state machine

As noted in the question, this comes from the C FAQs web site. The question is:

Q: How can I declare a function that can return a pointer to a function of the same type? I'm building a state machine with one function for each state, each of which returns a pointer to the function for the next state. But I can't find a way to declare the functions—I seem to need a function returning a pointer to a function returning a pointer to a function returning a pointer to a function…, ad infinitum.

A: You can't quite do it directly. One way is to have the function return a generic function pointer (see question 4.13), with some judicious casts to adjust the types as the pointers are passed around:

And then there's a first example using the code shown in the SO question.

As the FAQ answer says, you can't create a function that returns a pointer to its own type of function, so you have to bludgeon the compiler into working.

Line 1: typedef int (*funcptr)();

This has the () at the end because without them, you'd have typedef int (*intptr); or typedef int *intptr; which is not what you want. The empty parentheses are an indeterminate — not empty — list of arguments. It is the way you declare a function pointer — before even trying to compile with my default compilation options, I modified the code to: typedef int (*funcptr)(void);.

A funcptr, therefore, is a pointer to a function that returns an int and (at least for the purposes of this discussion) takes no arguments.

Line 2: typedef funcptr (*ptrfuncptr)();

Don't try this without the intermediate type! This too is a pointer to a function, and the function returns a funcptr — and I used typedef funcptr (*ptrfuncptr)(void); to assert 'and takes no arguments'.

Line 4 & 5: funcptr start(), stop(); etc

These lines declare a set of 5 functions. Again, the argument lists are unspecified — so I'm going to treat them as having (void). These functions return a funcptr. However, their own type is not funcptr. This is the point made in the answer.

Indeed, treated as a name (without the parentheses), the type of start, stop, and state1 through state3 is ptrfuncptr — pointer to a function returning a funcptr.

Line 9: ptrfuncptr state = start;

The variable state is of type ptrfuncptr, and is initialized (without need for casting) to point at the function start. Note that this does not call the function; it merely initializes a variable, just as if you have int i = -37;, it initializes a variable i of type int to the value -37.

Line 12: state = (ptrfuncptr)(*state)();

Time to get the bludgeons out. This line contains a function call and a cast.

The original logic behind function pointers was the 'type mimics use' concept. For example, if you have:

int *p;

then in an expression, *p has the type int. With function pointers, you have:

int (*intfuncptr)();

and in an expression, (*intfuncptr)() represents an int; it is the result of invoking the function pointed at by intptrfunc. In pre-standard C, the (*pointer_to_function)() notation was the only way to use a pointer to function. Standard C allows you to omit the (* and ) around the pointer.

Thus, in modern notation, the line state = (ptrfuncptr)(*state)(); could also be written state = (ptrfuncptr)state();. When I learned C, this wasn't an option, so I still prefer the explicit 'this is invoking a function via a pointer to function' notation. The FAQ does mention this.

So, the line calls the function pointed to by state, and captures the return value in state. But the value returned by the function is a funcptr, not a ptrfuncptr, so we need to bludgeon the compiler into accepting that we know enough of what we're doing to remain silent. So, the (ptrfuncptr) cast does that.

Line 17: return (funcptr)state1;

Since start returns a funcptr, but state1 is a pointer to a function that returns a funcptr, the cast here is, once more, necessary to bludgeon the compiler into accepting the type mismatch. Without parentheses after it, state1 is just the name of the function, not an invocation of the function, and therefore has the type ptrfuncptr — pointer to a function returning a funcptr, not just funcptr which is what start is supposed to return. So, the cast is necessary.

For more mind-blowing function pointers, see:

  • Understanding typedefs for function pointer in C — examples, hint and tips, please
  • How typedef works for function pointers
  • Is it a good idea to typedefpointers? — general answer, no, but there's a strong exception for pointers to functions.
  • What are the various styles of defining a function returning a function pointer?

…and somewhere there's a question that discusses trivia like state = (ptrfuncptr)(******state)(); (using notation from this Q&A), and the mulitple stars work too…

Function Pointer Memory Explanation in C

The best way to answer this is to look at the disassembly (slightly modified sample):

fptr1 = □
int result1 = fptr1(5);
int result2 = square(5);

Results in this x64 asm:

    fptr1 = □
000000013FA31A61 lea rax,[square (013FA31037h)]
000000013FA31A68 mov qword ptr [fptr1 (013FA40290h)],rax
int result1 = fptr1(5);
000000013FA31A6F mov ecx,5
000000013FA31A74 call qword ptr [fptr1 (013FA40290h)]
000000013FA31A7A mov dword ptr [result1],eax
int result2 = square(5);
000000013FA31A7E mov ecx,5
000000013FA31A83 call square (013FA31037h)
000000013FA31A88 mov dword ptr [result2],eax

As you can see the assembly is virtually identical between calling the function directly and via a pointer. In both cases the CPU needs to have access to the location where the code is located and call it. The direct call has the benefit of not having to dereference the pointer (as the offset will be baked into the assembly).

  1. Yes, you can see in the assignment of the function pointer, that
    it stores the code address of the 'square' function.
  2. From a stack
    setup/tear down: Yes. From a performance perspective, there is a
    slight difference as noted above.
  3. There are no branches, so there is no difference here.

Edit: If we were to interject branches into the above sample, it wouldn't take very long to exhaust the interesting scenarios, so I will address them here:

In the case where we have a branch before loading (or assignment) of the function pointer, for example (in pseudo assembly):

branch zero foobar
lea square
call ptr

Then we could have a difference. Assume that the pipeline chose to load and start processing the instructions at foobar, then when it realized that we weren't actually going to take that branch, it would have to stall in order to load the function pointer, and dereference it. If we were just calling a know address, then there would not be a stall.

Case two:

lea square
branch zero foobar
call ptr

In this case there wouldn't be any difference between direct calls vs through a function pointer, as everything we need is already know if the processor starts executing down the wrong path and then resets to start executing the call.

The third scenario is when the branch follows the call, and that is obviously not very interesting from a pipeline perspective as we've already executed the subroutine.

So to fully re-answer question 3, I would say Yes, there is a difference. But then the real question is whether or not the compiler/optimizer is smart enough to move the branch after the function pointer assignment, so it falls into case 2 and not case 1.

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

How does #define work with function pointers?

This directive

#define kkData (*SomeFunc());

means a call of the function SomeFunc and dereferencing the pointer to a structure returned from the function.

For example you could write in the program

SomeStructure s = kkData

Pay attention to that the semicolon in the directive should be removed. In this case the code in the program

SomeStructure s = kkData;

will be more clear.

How to define a function pointers and and structure?

One possible way:

//do the typedef first, on a forward declaration
typedef struct INFOS_STRUCT INFOS_STRUCT
typedef void (*PTR_ACTION)(INFOS_STRUCT * infos);
typedef PTR_ACTION (*PTR_NEXT_ACTION)(INFOS_STRUCT * infos);
struct INFOS_STRUCT {
int val1;
PTR_NEXT_ACTION nextAction;
};

Note: Changed the tag from _INFO_STRUCT to INFO_STRUCT. _INFO_STRUCT is a reserved name. You could use INFO_STRUCT_ (not reserved) if you need the tag to differ from the typedef name.


Explanation:

The idea is simple. Once you forward declare a struct or union like with:

struct foo; 
union bar;

You can declare/define pointers to it such as

struct foo *ptr0;
union bar ***ptr1;

If the pointer definitions are in another struct/union definition that's at the same scope or at just plain in the same scope scope, you don't even need the forward declaration (note that function parameters, even in a declaration, are in a nested scope, so you do need the forward declaration in struct foo; void takefooptr(struct foo*);).

When you then follow a forward declare struct foo with struct foo { /*...*/ }; the type gets completed and you can start declaring actual struct foo variables rather than just pointers.

If want to skip the struct/union keyword in later uses, you can typedef the forward declaration:

struct foo;
typedef foo foo; //or typedef foo SOMENEWNAME;

or do it in one step

typedef struct foo foo;

As a quirk of the C standards, this forward-declaration thing is not allowed for enums. Structs and enums only.



Related Topics



Leave a reply



Submit