Say I want to implement a numerical integration routine with plain C. That will look something like this:
double integrate(double (*f)(double), double lower, double upper, double step));
I often find functions that actually depend on multiple variables, and I want to integrate over the first one. Say I want to integrate this:
double func(double x, double z);
with respect to x
. I cannot pass func
to integrate
since it has the wrong signature. Now I know the following workarounds, which were employed by us when we took the numerics course:
Use C++
I just have used C++ and ist std::bind
to create a functor (function object) that I could pass to the integration routine. Now I would just use the lambda functions to get it done.
Use GCC extension for functions in function
With GCC, you can declare a function in a function. So one could do
// z is set to some value in this function scope here.
double inner(double x) {
return func(x, z);
}
and pass that inner
to the integrate
function. That is non-standard and does not feel so well.
Use global variables
The value of z
could be stored in a global variable. That would require the function func
to be editable to use z
from the global variables instead of the parameter. That might not be possible. Then it also breaks concurrency and is just bad in general.
Does a way exist to do with in plain C without breaking something?
One common solution to this problem is to change the design into this:
double integrate(double (*f)(double, void*), void*,
double lower, double upper, double step);
Here you pass an additional void *
to integrate
, and this is being passed back to f
. This can be used to pass arbitrary data around, in your case you would pass a pointer to z
, and within the function f
you would cast the pointer back to its original type and recover the value z
. This pattern is ubiquitous within C libraries, for example here is the prototype of pthread_create:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With