p0llard
p0llard

Reputation: 459

Why must function pointers be used?

What is the need for function pointers? The standard answer for this seems to be callbacks, but why can't we just pass a function?

The book I was reading on C++ demonstrates passing a function as a parameter, and acknowledges that in actual fact the compiled turns this into a function pointer and passes that instead, because functions are not actual objects. It showed the equivalent code using function pointers, which was slightly more complex - if the code is equivalent, why bother to use a function pointer.

I presume there is a case when is simply isn't possible to pass the function, and one must pass a pointer instead? Can someone give me an example of this case, as it would help me understand why function pointers are useful.

Consider the following code:

#include <iostream>

using namespace std;

int add(int x) {
        return ++x; //this is a copy, so it doesn't touch x
}

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


int main() {
        runprint(add, 1);

        return 0;
}

We are passing a function as a parameter, not a pointer. The function accepting the function (!), is not accepting a pointer.

Upvotes: 3

Views: 1112

Answers (3)

parisa nikzad
parisa nikzad

Reputation: 1

Function pointer is a pointer that holds the address of the function. Function pointer is to invoke the function even if the name of the function is unknown. This is practical in using different function at runtime.

Upvotes: 0

anatolyg
anatolyg

Reputation: 28241

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".

Upvotes: 3

Peter - Reinstate Monica
Peter - Reinstate Monica

Reputation: 16016

function is considered a function pointer by g++:

$ cat fp.cpp
#include <typeinfo>
#include <iostream>

using namespace std;

int add(int x) {
        return ++x; //this is a copy, so it doesn't touch x
}

void runprint(int function(int x), int x) {
        cout << typeid(function).name() << endl;
        int (*f)(int);  // function pointer compatible with function argument
        f = function;
        cout << typeid(f).name() << endl;
        cout << function(x) << endl;
}


int main() {
        runprint(add, 1);

        return 0;
}
$ g++ -Wall -std=c++11 -o fp fp.cpp
$ ./fp
PFiiE
PFiiE
2

Upvotes: 3

Related Questions