1

So I need to write some code that performs partial integration. I have a numerical integrator schematically represented by

double integrate(double (*func)(double));

and suppose it works properly, i.e. for a function double f(double x), integrate(f) gives the right result. What I have instead, however, are functions that look like

double f(double x, double y);

and I want to perform integration on only the first variable - so dynamically generate pointers to functions like g(x)=f(x,1) or h(x)=f(x,2) and pass them to integrate. I guess prototypically what I want is to define a function within another,

double compute(double y){
  double g(double x){
    return f(x, y);
  }
  return integrate(g);
}

which I know is not part of ANSI C even though GCC allows it (maybe I shouldn't care and just use it then). So, what would be the standard, C18 approved way to get this behavior? If the only possibility is to copy over the code of integrate to the inside of compute, I guess I'll just use the GCC extension even though my LSP constantly complains about it, but I'm interested in what the "proper" program would look like.

1 Answers1

2

Using the base C language, that is code that is strictly conforming as the standard defines it, here are three ways to do it.

Define a function that hard-codes the additional argument:

double g1(double x) { return f(x, 1); }
…
integrate(g1);

Define a function that gets the additional argument from an externally defined object:

double y;
double g(double x) { return f(x, y); }
…
y = 1;
integrate(g);

Modify integrate to take a pointer to additional information and use that to pass information to the function being integrated:

double integrate(double (*func)(double, const void *))

struct MyData { double y; }; // This structure can contain whatever you want.

double g(double x, const void *p)
{
    const struct MyData *data = p;
    return f(x, data->y);
}
…
struct MyData data = { 1 };
integrate(g, &data);

With GCC, you can use one of its extensions beyond the C standard that allows you to define functions within functions:

double compute(double y)
{
    double g(double x) { return f(x, y); }
    return integrate(g);
}

That can also be done in Clang using the blocks extension, but that would also require modifying integrate to accept a block.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    Important to note that even in GCC it does not do proper closures and you may not return `g` out of the function so still of limited utility and not much better than using the global variables. – Antti Haapala -- Слава Україні Aug 30 '22 at 20:34
  • 2
    Another approach is to have a function accept a pointer to a callback function pointer, and have it pass the received pointer to that function. If the function pointer is the first member of a structure type which is known to the callback function and the code which generates the object encapsulating the method, the callback function can cast the received pointer to that structure type. – supercat Aug 30 '22 at 22:07