Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
953 views
in Technique[技术] by (71.8m points)

c - Currying/binding with ISO C99

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...