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 voids 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) { ... }