简体   繁体   中英

Passing function into another as a pointer with different length arguments?

In file1.h

// find the root of a function of one variable
double rootfind(double (*fp)(double), double start, double end);

In file2.h

// a function of multiple variables
double myfun(double a, double b);

double test();

In file2.c

double myfun(double a, double b)
{
    return (a+3.0)*(a-1.0)*(a-1.0)*b;
}

double test()
{
    double b, start, end;

    start = -4.0;
    end = 4.0/3.0;

    b = 2.0;

    // How do I use the rootfinding function to find the root of myfun
    // where b is set as a constant in this function?
    // How do i find the root of myfun(x,2.0)?
}

I want to keep the rootfind function generic and not pass extra parameters in. I also don't want to use the gcc extension for nested functions.

You are asking about something known as closures which are not supported in standard C90/C99. If you do plan on doing this, you either have to:

  • Use the GCC extension you mentioned.
  • Use C++'s std::bind function.
  • Use a library (such as libffi that comes with GCC) to allocate memory that can be written to and run (you create the machine code for the new one argument function at runtime).
  • Write a top level static function that works the way you want it to.
  • Use a dynamically loaded module that you compile from C code at runtime.

Most of those probably seem confusing/intimidating, that's because there's really no good way to do what you want in C. This is mostly because it's very dangerous (major security hole) to have functions rewritten at run time in C.


An example of a top level static function (place this just above your main function):

static myfun_single_b = 2.0;

static double myfun_single(double a) {
    return myfun(a, myfun_single_b);
}

The reason we use the static keyword here is so that the name of the variable and the name of the function won't conflict with other function/variable names from other source files.

You can write a wrapper function:

static double wrapper(double a) {
    return myfun(a, 3.0);
}

and use rootfind() on that. You could make it more general (ie to support different values of the second argument to myfun() ) by making it take the value of myfun() 's second argument from a file-scope variable:

static double b;

static double wrapper(double a) {
    return myfun(a, b);
}

You could even generalize it more by making the wrapper call a two-arg function via a file-scope function pointer:

static double b;
static double (*wrapped)(double, double);

static double wrapper(double a) {
    return (*wrapped)(a, b);
}

That's about the limit of the indirection you can perform, but it affords a fair amount of latitude.

If you can modify rootfind , the proper way to fix it would be to add a context parameter to the function pointer, like

double rootfind(double (*fp)(double, void *), double start, double end, void *context);

You can then create a context struct containing your second argument b and pass a pointer to it via the context argument.

This way, both global state and run-time code generation are avoided. The rootfind function also remains generic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM