Search code examples
cpointersparameter-passingfunction-pointers

Call a function using a pointer and pass the pointer that can point to the function along in the parameters


Say that I have a pointer to function theFunc. theFunc takes along a pointer that can point to any function with the same parameter list as theFunc, so the function called can set the passed pointer to NULL or a different function.

Using it would look like this:

while (funcPtr != NULL)
{
    funcPtr(&funcPtr);
}

Would defining this be impossible?


Solution

  • Yes, it's doable.

    The simple way:

    void (*fptr_t)(void*);
    

    The function pointer is data, even though it point to non-data. Therefore a pointer to function pointer can be converted to void* without relying on compiler extensions.

    This solution lacks type safety. However, it can be improved.

    Currently, it is possible to declare a function taking unspecified number of parameters. It allows to form an incomplete function type. For example:

    int foo();
    

    declares a function that returns int and takes unspecified parameters. To have a function taking no parameters use int foo(void).

    This allows to declare a function taking a pointer to pointer to incomplete function type:

    int foo(int (**)());
    
    // call
    int (*fptr)(int (**)()) = foo;
    fptr(&fptr);
    

    As mentioned in other answers typedef-ing function types makes the code cleaner.

    typedef int foo_aux_f();
    typedef int foo_f(foo_aux_f**);
    
    foo_f *fptr = &foo;
    
    fptr(&fptr);
    

    It is possible to improve type safety by nesting the declaration of function types deeper and deeper.

    typedef int foo_aux0_f();
    typedef int foo_aux1_f(foo_aux0_f**);
    typedef int foo_aux2_f(foo_aux1_f**);
    typedef int foo_aux3_f(foo_aux2_f**);
    typedef int foo_f(foo_aux3_f**);
    
    foo_f fptr = &foo;
    fptr(&fptr);
    

    The perfect recursive type would be reached with infinite chain of declaration but in practice 2-3 levels are sufficient.

    With some abuse of the syntax of typedef keyword it is possible to squeeze the declaration of this type:

    typedef int foo_aux0_f(),
                foo_aux1_f(foo_aux0_f**),
                foo_aux2_f(foo_aux1_f**),
                foo_aux3_f(foo_aux2_f**),
                foo_f(foo_aux3_f**);
    

    Unfortunately ... or fortunately, this trick will likely not work in upcoming C23 because the old function declarations without prototypes are planned to be removed from the language making () mean no arguments rather then unspecified number of argument.