How to make a function which receive other function as param (with no known parameters)

旧巷老猫 提交于 2019-12-11 03:14:54

问题


Previously I asked How to make a function which receive a function as param in C language. I get an answer Link to the question but this solution is based on the parameters of argument's function. I mean:

int functionToPassAsParameter (int arg1, int arg2){
    // do something
}

int functionWhichReceiveFunction (int (*f)(), int arg1, int arg2){
    // do something
    f(arg1, arg2);
    // do something
}

// How to call the function
functionWhichReceiveFunction (&functionToPassAsParameter, 1, 2);

I would like something like:

int functionToPassAsParameter (int arg1, int arg2){
    // do something
}

int functionWhichReceiveFunction ( f() ){
    // do something
    f();
    // do something
}

// How to call the function
functionWhichReceiveFunction ( functionToPassAsParameter(arg1, arg2) );

So, when I call the function, I pass the correctly params but when I define the function which receive the other function I do not specify which params I will send to it. Is that possible to make?


EDIT 1: I wanna achieve pass any function to functionWhichReceiveFunction. Something like:
int function_a (int param1, int param2) { /* Do something */ };
void function_b (char *arg1) { /* Do something */ };

// Call the function with two differents functions regardless return type nor params
int x = functionWhichReceiveFunction ( function_a(param1, param2) );
functionWhichReceiveFunction ( function_b(arg1) );

回答1:


Define the function to be passed to take a void * as a parameter. That way the function that calls the given function doesn't need to know anything specific about the parameters:

struct params1 {
   int arg1;
   int arg2;
};

struct params2 {
   char *arg1;
   char *arg2;
};

int functionToPassAsParameter (void *param){
    struct params1 *args = params;
    // do something
}

int otherFunctionToPassAsParameter (void *param){
    struct params2 *args = params;
    // do something
}

int functionWhichReceiveFunction (int (*f)(void *), void *args) {
    // do something
    f(args);
    // do something
}

struct params1 p1 = { 1, 2 };
functionWhichReceiveFunction (&functionToPassAsParameter, &p1);
struct params2 p2 = { "abc", "def" };
functionWhichReceiveFunction (&otherFunctionToPassAsParameter, &p2);



回答2:


To be able to pass a function with unknown parameters to a function, declare the function that will pass the function as follows:

int g(int (*f)());

The function that is actually passed can have any number of parametes, for example:

int f(int x, void *y);

The call is now as follows:

g(f);

The above means that g passes f, which can have zero or more parameters of any type. This is denoted by the empty parameter list.

A particular function that may need to be passed is for example f.

Now g is called with function f, or any other function.

Note that it is up to g to know which parameters must be passed in calling f. So you need a "protocol" that tells g which function/type is passed. For example, besides passing the function, pass an identifier (int) that says what type of function is passed, for example:

#define fS_I_I  1   // f needs String, int, Int
#define fD_I    2   // f needs Double, Int
#define fI_I    3   // f needs Int, Int

int g(int ID, int (*f)());

g(fI_I, f);



回答3:


Learn more about closures and tagged unions. Notice that C don't have them. You might want to emulate that with callbacks

I wanna achieve pass any function to functionWhichReceiveFunction

You cannot do that simply and portably. Remember that the signature of a function in C is related to its calling conventions (so to the ABI used by your compiler and your code; for examples, look into Linux x86 ABIs; so floating point arguments could be passed in different registers as integral arguments, so your compiler needs to know the signature of all your function pointers). You need to also give to functionWhichReceiveFunction something which describes the signature.

What you might consider doing, assuming your platform have function pointers of the same size and in the same address space as data pointers (this is very often the case), is to pass to functionWhichReceiveFunction a void* pointer (actually, a function pointer casted to void*) and an enumeration describing it.

For example

enum funsig_en {
  funsig_void_to_void,
  funsig_int_to_void,
  funsig_int_to_double,
  funsig_int_double_to_void,
};

Then, you'll have corresponding function signatures (types)

typedef void fun_void_to_void(void);
typedef void fun_int_to_void(int);
typedef double fun_int_to_double(int);
typedef void fun_int_double_to_void(int, double);

Suppose you have these static functions

static void statf_void_to_void(void);
static void statf_int_to_void(int);
static double statf_int_to_double(int);
static void statf_int_double_to_void(int, double);

You might declare

void 
functionWhichReceiveFunction (void*res, enum funsig_en sigkind, void*fun, ...);

and you could use it as

functionWhichRecieveFunction(NULL, funsig_void_to_void
                             (void*)statf_void_to_void);

or

functionWhichRecieveFunction(NULL, funsig_int_to_void, 
                             (void*)statf_int_to_void, 123);

or

double r = 0;
functionWhichRecieveFunction(&r, funsig_int_to_double, 
                             (void*)statf_int_to_double, 2345);

I leave you to code that variadic functionWhichRecieveFunction. You need stdarg(3) facilities. It would include code like

va_args arglist;
va_start (arglist, fun);
switch(sigkind) {
case funsig_int_to_void: {
  int a = va_arg(arglis, int);
  fun_int_to_void* fptr = (fun_int_to_void*)fun;
  (*fptr)(a);
  return;
} // end case funsig_int_to_void

much later you'll need some va_end(arglis); near the end of your functionWhichRecieveFunction body.




回答4:


Another possibility is using varargs. In the following example every function being called does its own interpretation of parameters.

#include <stdio.h>
#include <stdarg.h>

// expects 4 arguments (int, int, int, char*)
void f1(va_list args) {
    int a, b, c;
    char *d;

    a = va_arg(args, int);
    b = va_arg(args, int);
    c = va_arg(args, int);
    d = va_arg(args, char *);

    printf("%d, %d, %d: %s\n", a, b, c, d);
}

// expects 3 ars (int, int, char*);
void f2(va_list args) {
    int a, b;
    char *c; 

    a = va_arg(args, int);
    b = va_arg(args, int);
    c = va_arg(args, char *);

    printf("%d, %d: %s\n", a, b, c);
}



void caller(void (*f)(va_list), ...) {
    va_list args;

    va_start(args, f);
    f(args);
    va_end(args);
}


int main() {
    caller(&f1, 0, 1, 3, "hello");
    caller(&f2, 1, 2, "bye");
    return 0;
}

Another possibility is to have caller to interpret parameters based on some type info and call a correct function call. This might be useful if you have a limited number of argument patterns and just regular functions to call:

void f3(int a, int b, int c, char *d) {
    printf("%d, %d, %d: %s\n", a, b, c, d);
}

void f4(int a, int b, char *c) {
    printf("%d, %d: %s\n", a, b, c);
}

typedef enum  {
    type1, type2
} Types;

void caller1(Types t, void (*f)(), ...) {
    va_list args;

    va_start(args, f);
    switch (t) {
    case type1: {
        int a, b, c;
        char *d;

        a = va_arg(args, int);
        b = va_arg(args, int);
        c = va_arg(args, int);
        d = va_arg(args, char *);

        f(a,b,c,d);
        break;
    }
    case type2: {
        int a, b;
        char *c;

        a = va_arg(args, int);
        b = va_arg(args, int);
        c = va_arg(args, char *);

        f(a,b,c);
    }
    }
    va_end(args);

}

int main() {

    caller1(type1, &f3, 3,2,1, "hi");
    caller1(type2, &f4, 3,2,"take care");

    return 0;



回答5:


@Paul Ogilvie, this is the code:

int f(int x, void *y) {
    return x;
};


int g(int (*f)()) {
    int x = f(1, NULL);     // call f with parameters
    printf("X is: %d", x);
    return(x);              // return result
};

int main()
{
    //g( f(1, 2) );   // this passes the result of a call to f, not f
    g( f );           // this passes f
    return 0;
}


来源:https://stackoverflow.com/questions/52817011/how-to-make-a-function-which-receive-other-function-as-param-with-no-known-para

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!