Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining a function which returns a function pointer which also returns a function pointer without typedefs

I am trying to really understand function pointers without using typedef but cannot seem to get this. I do not understand what signature is needed to convey that I return a pointer to a pointer to a function.

#include <stdio.h>

void odd()  { printf("odd!\n");  }
void even() { printf("even!\n"); }

void (*get_pfn(int i))()
{
    return i % 2 == 0 ? &even : &odd;
}

__SIGNATURE__
{
    return &get_pfn;
}

int main()
{
    get_pfn_pfn()(1)();
    get_pfn_pfn()(2)();
    return 0;
}

To make this work, what does __SIGNATURE__ have to be?

like image 661
Jas Avatar asked Sep 10 '19 17:09

Jas


People also ask

How can a function return a pointer to a function?

Return Function Pointer From Function: To return a function pointer from a function, the return type of function should be a pointer to another function. But the compiler doesn't accept such a return type for a function, so we need to define a type that represents that particular function pointer.

Can we declare a function that can return a pointer to a function of the same type?

You cannot return a function in C - you return a pointer to a function. If you mean to define a function which returns a pointer to a function which again returns a pointer to a function and so on, then you can use typedef to implement it.

Which of the following declares a pointer to a function which returns a pointer to an integer?

int (*f) (int * ): A pointer to a function that takes an integer pointer as argument and returns an integer.

How do you declare a function pointer that takes an integer argument and returns a character?

Function Pointer Syntaxvoid (*foo)( int ); In this example, foo is a pointer to a function taking one argument, an integer, and that returns void. It's as if you're declaring a function called "*foo", which takes an int and returns void; now, if *foo is a function, then foo must be a pointer to a function.


2 Answers

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;
}
like image 163
KamilCuk Avatar answered Sep 30 '22 15:09

KamilCuk


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) { ... }
like image 35
dbush Avatar answered Sep 30 '22 16:09

dbush