0

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.

5
  • The question and the prose doesn't match. Do you want to pass a pointer to pointers to void functions or a pointer to pointer to function? Commented Feb 10, 2023 at 19:12
  • Please edit your question to supply a program i.e. minimal reproducible example instead of a snippet Commented Feb 10, 2023 at 19:26
  • 2
    BTW, do not use double underscores to prefix identifiers. It's undefined behavior. C is not Python :-) Commented Feb 10, 2023 at 20:10
  • aka: "How to make simplicity complicated" You've not shown how you'll prevent attempting to invoke a NULL pointer to a function... Remember KISS... (btw: probably a typo in assigning NULL to f1 at the the end of the function... AND look carefully at the last strcmp() parameters, too...) Commented Feb 10, 2023 at 20:15
  • To clarify, where you use ... in function parameter lists in your examples, you don't actually mean that the functions involved are variadic, do you? Commented Feb 10, 2023 at 20:15

2 Answers 2

3

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 */);
}
Sign up to request clarification or add additional context in comments.

Comments

1

Assuming the functions take the same number and type of arguments¹, you can declare an array of function pointers and assign to each pointer the address of a function:

void (*foo[SIZE]) (void) = { &f1_mod, &f2_mod,
                             &f3_mod, &f4_mod };

Pass the array to the function as:

__thefunctioniwouldlike (foo);

The function declaration can be written as:

void __thefunctioniwouldlike (void (*foo[]) (void), ...);

Then assign it to __f1__ as:

__f1__ = foo[0];

In a similar vein, instead of passing the char * as separate arguments, you can declare an array of char *s:

char *ret[SIZE] = { "mod1", "mod2", "mod3", "mod4" };

Pass it to the function as:

__thefunctioniwouldlike (foo, ret);

The function declaration can be written as:

void __thefunctioniwouldlike (void (*foo[]) (void), char *ret[]);

Compare the string pointed to by the pointer as:

strcmp (ret[0], "foo1");

Execute the function pointed to by the zeroth member of the array as:

(*foo[0])();

Or simply:

foo[0]();

Sample code:


/* Note: I am not very fond of `typedef`s, 
*        but they could help with readability here. 
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void f1_mod (void) { }
static void f2_mod (void) { }
static void f3_mod (void) { }
static void f4_mod (void) { }

static void func (void (*foo[])(void), char *ret[], void (**tmp)(void)) {
   if (!strcmp (ret[0], "mod1")) {
       *tmp = foo[0];
   }
    
}

int main (void) 
{ 
    void (*foo[]) (void) = { &f1_mod, &f2_mod, &f3_mod, &f4_mod };
    
    void (*tmp) (void) = 0;
    
    char *ret[] = { "mod1", "mod2", "mod3", "mod4" };
    
    func (foo, ret, &tmp);
    return EXIT_SUCCESS;
}




[1] — If that's not true, you can still follow the same approach, and call internal functions inside with the relevant arguments.

For example:

static void f1_mod1 (void) 
{
    f1_mod1_internal (...);
}

2 Comments

Your example program is missing <string.h>, and more importantly only modifies the value of tmp local to func.
@Oka One wouldn't go wrong when one has such peers. :) I edited the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.