Defining a function which returns a function pointer which also returns a function pointer without typedefs
It has to return a function pointer to a function that takes an int
and returns a function pointer:
void (*(*get_pfn_pfn(void))(int))(void) {
return &get_pfn;
}
more lines:
void (*
(*
get_pfn_pfn(void) // this is our function
)(int i) // this is get_pfn(int)
)(void) // this is odd() or even()
{
return &get_pfn;
}
The void
s can be omitted, in which case the function pointer points to a function that takes unknown number of parameters. Which is not what you want. To declare a function pointer to a function that takes no arguments, you should add void
inside function parameter list. The same way it's best to change get_pfn
to void (*get_pfn(int i))(void)
. For example try calling from get_pfn(1)("some arg", "some other arg");
. A C compiler will not give a warning, as empty ()
denote unknown arguments. To say that function takes no arguments, you have to (void)
.
For many the sequences of braces, especially ))(
, in function pointers are hard to parse. That's why many prefer typedefs for function pointers or types:
typedef void get_pfn_func_t(void);
get_pfn_func_t *get_pfn(int i) {
return i % 2 == 0 ? &even : &odd;
}
typedef get_pfn_func_t *get_pfn_pfn_func_t(int i);
get_pfn_pfn_func_t *get_pfn_pfn(void) {
return &get_pfn;
}
The return type of the function get_pfn
is -
void (*) ();
So type of &get_pfn
is -
void (*(*)(int))()
Now, this function returns this type, hence its signature will be -
void (*(*(foo)())(int))()
You can verify this by typing this in cdecl.org
Function pointers without a typedef
can be tricky to work with. To figure them out, you work from the inside out.
So let's break down exactly how we come up with the correct function signature.
get_pfn_pfn
is a function:
get_pfn_pfn()
Which takes no parameters:
get_pfn_pfn(void)
And returns a pointer:
*get_pfn_pfn(void)
To a function:
(*get_pfn_pfn(void))()
Which takes an int
parameter:
(*get_pfn_pfn(void))(int)
And returns a pointer:
*(*get_pfn_pfn(void))(int)
To a function:
(*(*get_pfn_pfn(void))(int))()
Which takes no parameters:
(*(*get_pfn_pfn(void))(int))(void)
And returns nothing (i.e. void
):
void (*(*get_pfn_pfn(void))(int))(void)
Of course, using typedef
's simplifies this greatly.
First the type for even
and odd
:
typedef void (*func1)(void);
Which we can then apply to get_pfn
:
func1 get_pfn(int) { ... }
Then the type for this function:
typedef func1 (*func2)(int);
Which we can apply to get_pfn_pfn
:
func2 get_pfn_pfn(void) { ... }