Search code examples
cfunctionpointersfunction-pointersvoid-pointers

Passing pointer to function to function and assign it in C


I have a program in which te type of function to be used has to be different according to a string (the mode). Suppose i want the functions in extfunc to be initiated according to the value i write in some strings, that i have the following situation.

I have a number of functions

void f1_mod1(...)
{
    //do domething
}

void f1_mod2(...)
{
    //do something else
}

void f2_mod1(...)
{
    //do something 2
}

void f2_mod2(...)
{
    //do something 2
}

and I want them to be used according to some configurational strings fXn, where X = 1, 2, as in

void extfunc(...)
{
    // ...
    char *f1n = "mod1";
    char *f2n = "mod2";
    void (*__f1__)(), (*__f2__)();
    __thefunctioniwouldlike(f1n, __f1__, f2n, __f2__);
    // execute f1_mod1
    __f1__(...);
    // execute f2_mod2
    __f2__(...);
}

where

void __thefunctioniwouldlike(char *f1n, void *__f1__, char *f2n, *__f2__)
{
    if (strcmp(f1n, "mod1") == 0)
        __f1__ = f1_mod1;
    else if (strcmp(f1n, "mod2") == 0)
        __f1__ = f1_mod2;
    else 
        __f1__ = NULL;
    if (strcmp(f2n, "mod1") == 0)
        __f2__ = f2_mod1;
    else if (strcmp(f1n, "mod2") == 0)
        __f2__ = f2_mod2;
    else 
        __f1__ = NULL;
}

is a function that takes the configurational strings and assign the function pointers to one of my functions above so that when they are called execute the assigned function.

For completeness:

fX_modX are the functions that take certain arguments and do different stuff both based on the mod variable fXn encoded in a string and __thefunctioniwouldlike is a function that takes as argument the pointers to functions to initiate them according to the value of strings fXn. How can i pass the pointer to pointers to void functions void (*__f1__)() so that in the end executing __fX__ in extfunc will execute fX_modY or fX_modY based on the assignment inside __thefunctioniwouldlike?

Thanks in advance.


Solution

  • How can i pass the pointer to pointers to void functions void (*__f1__)() so that in the end executing __fX__ in extfunc will execute fX_modY or fX_modY based on the assignment inside __thefunctioniwouldlike?

    As ever, in C function arguments are passed by value. If you want a called function to modify an object that is local to the caller, then you must pass the address of that object to the function, and the function must modify it indirectly. That applies just the same when that object has pointer type, including function pointer type, as when it has any other type.

    Type names can get pretty hairy, however, especially when function pointers are involved. Typedefs can help. I would recommend something along these lines:

    // declare f1_func and f2_func as aliases for function types
    typedef void (f1_func)(/* ... f1 parameters ... */);
    typedef void (f2_func)(/* ... f2 parameters ... */);
    
    // the actual functions must have parameter lists matching the expected ones
    // for the corresponding typedefed function types
    
    void mod1_f1(/* parameters */) {
        // ...
    }
    
    void mod1_f2(/* parameters */) {
        // ...
    }
    
    void mod2_f1(/* parameters */) {
        // ...
    }
    
    void mod2_f2(/* parameters */) {
        // ...
    }
    
    // Functions cannot be handled as objects.  You need to use function pointers, instead,
    // such as a f1_func * or a f2_func *.
    //
    // But then you need a second level of indirection to allow a function to manipulate
    // function pointers that are local to the caller.
    void set_module_functions(const char *f1_module, f1_func **f1,
            const char *f2_module, f2_func **f2) {
        // Note: Function names such as mod1_f1 are automatically converted to pointers
    
        // in some case:
        *f1 = mod1_f1;
        // in another case:
        *f1 = mod2_f1;
    
        // in some case:
        *f2 = mod1_f2;
        // in another case:
        *f2 = mod2_f2;
    }
    
    void the_caller(/* ... */) {
        f1_func *f1;
        f2_func *f2;
    
        // Pass the addresses of the function pointers:
        set_module_functions("mod1", &f1, "mod2", &f2);
    
        // Functions can be (in fact, always are) invoked through function pointers.
        // There is no need to dereference a function pointer to call the pointed-to
        // function.
        f1(/* arguments */);
        f2(/* arguments */);
    }