Reputation: 4955
EDIT: It's been pointed out that this question is sort of confusing. The short version is: "why have a separate pointer variable (eg, fnPtr
) which points to a function (eg, fn
) when the function name fn
itself, without arguments, is already a pointer? /EDIT
I'm trying to understand something and could use feedback from the community regarding function pointers. (And while this might look like a duplicate of other questions on the topic, it really isn't, as least not that I could find.)
I understand the concept of a pointer to a function being used as an argument to another function as a callback...ie telling fn1
to use fn2
in some way during the execution of fn1
. What I don't understand is the complex syntax being used in all of it. If fn
is a defined function, then calling fn(...)
will execute the function with the supplied arguments. However, fn
used on its own is the address of the function, that is, a pointer to the function. Furthermore, fn
, &fn
, and *fn
are all the same thing. Why have dedicated function pointers, and why create new variable (ie, fnPtr
) which point to a function...the function name is already its own pointer!
This code compiles and works the same every time.
#include <stdlib.h>
#include <stdio.h>
int fn(int var) { //fn is a function which takes an int and returns an int
return var;
}
int (*fnPtrAmp)(int) = &fn;
int (*fnPtr)(int) = fn;
int needsCallback(int variable, int callback(int)) {
return callback(variable);
}
int needsCallbackPointer(int variable, int (*callbackPtr)(int)) {
return callbackPtr(variable);
}
int needsCallbackPointerWithDereference(int variable, int (*callbackPtr)(int)) {
return (*callbackPtr)(variable);
}
int main() {
printf("%d\n", fn(4));
printf("%d\n", fnPtr(4));
printf("%d\n", (*fnPtr)(4));
printf("%d\n", needsCallback(4,fn));
printf("%d\n", needsCallbackPointer(4,fnPtr));
printf("%d\n", needsCallbackPointer(4,fn));
printf("%d\n", needsCallbackPointer(4,&fn));
printf("%d\n", needsCallbackPointerWithDereference(4,fnPtr));
printf("%d\n", needsCallbackPointerWithDereference(4,fn));
printf("%d\n", needsCallbackPointerWithDereference(4,&fn));
return 0;
}
The simplest syntax is that of needsCallback
but that isn't done anywhere, it's always needsCallbackPointer
and fnPtrAmp
. Why? With needsCallback
you don't even have to define an extra variable to be the function pointer. As I said before, the function name is its own pointer!
Could use some feedback...thanks.
Upvotes: 2
Views: 839
Reputation: 7486
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.
"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.
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.
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.
*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.)
Upvotes: 4
Reputation: 14843
The purpose of function pointer syntax in C is two fold
1) To confuse programmers
2) To allow the compiler to syntax check that the callers of function pointers use the same arguments as the functions themselves.
The second is what leads to most of the confusion, since if you have a function pointer that returns a pointer then the binding of the derefence (*) doesn't work as expected, and you have to add the extra parentheses.
-A
Upvotes: 0