3

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?

Martin Ueding
  • 8,245
  • 6
  • 46
  • 92

5 Answers5

4

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);
pentadecagon
  • 4,717
  • 2
  • 18
  • 26
3

No, C has no way to do this at the level of C functions/C function pointers. The best way to do it for a particular application (like mathematical functions and integration) would be to use your own structures to represent mathematical functions, and any variable slots that are already bound. I would probably not make the functions take varying numbers of arguments, but instead a pointer to an array of arguments; this makes it a lot easier to call them programmatically in different ways.

Alternatively you could use something like libffi which can do this kind of binding/closures, but it's definitely not portable or efficient.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
2

Your problem can also be solved with variable arguments functions (and slightly more effort):

#include <stdarg.h>

double integrate(double (*f)(double, ...), double lower, double upper, double step)
{
    return (f)(lower, upper);
}

double func1(double x, ...)
{
    va_list ap;
    double ret;

    va_start(ap, x);

    ret = x * va_arg(ap, double);

    va_end(ap);

    return ret;
}

double func2(double x, ...)
{
    return x;
}

Although not sure if I should consider that in any way cleaner...

mfro
  • 3,286
  • 1
  • 19
  • 28
0

I'm 99% sure it's not possible with pure C89. In order to do this, you have to create a new function pointer at runtime. There are two ways to get a function pointer: from a function expression, or from a standard library function that returns a function pointer. Function expressions refer to functions defined at compile time, so that won't work. The only standard library function that returns a function pointer is signal, and that's no help because you only get out of it what you put in.

The only other way to get a new function pointer would be to convert a pointer to an object type into a function pointer, and that's not portable because it's not in the list of pointer conversions that you can do (however, it is noted as a common extension).

For a little while I thought you might be able to get somewhere with setjmp and longjmp, but that just replaces the problem of storing the double with the problem of storing the jmp_buf.

I did get something that happens to work on my system today, but since it's nonportable even upgrading my compiler might break it. The general idea is to create a structure that contains the pointer to the original function, the double z, and some machine code to access that information and call the original. I don't suggest you use this, but I found it interesting. I've pointed out some of the unportable assumptions in the comments.

/* platform-specific include */
#include <sys/mman.h>
/* standard includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

double func(double x, double z)
{
    printf("%g\n", z);
    return x;
}

double bar(double x)
{
    printf("y\n");
    return x;
}

double call(double (*f)(double))
{
    return f(0.0);
}

struct cDblDblRetDbl
{
    double (*function)(double, double);
    double a;
    char code[1];
    double pad;
};

static double helper(double x)
{
    /* Casting a function pointer to an object pointer is
     * not provided by the standard.
     * In addition, this only works because the compiler
     * happens to use RIP-relative addressing, so "helper"
     * points to the beginning of the currently executing
     * function, which is actually a copy of the one in
     * the object file.
     * It's worth noting explicitly that nothing in the
     * C standard says that a pointer to a function will
     * point to its machine code.
     */
    double *dp = (double *) helper;
    struct cDblDblRetDbl *data;
    /* Modify it to point after the structure.
     * This depends on the alignment and padding of the
     * structure, which is not portable.
     */
    dp += 2;
    data = (struct cDblDblRetDbl *) dp;
    /* back it up to the structure */
    --data;
    /* now call the function with the saved data. */
    return data->function(x, data->a);
}

/* There is no way to get the code size of a function,
 * so this is very nonportable.
 * I found it by examining the object file.
 */
#define CODE_SIZE 0x60

double (*curryDoubleDoubleReturningDouble(double (*function)(double, double), double a))(double)
{
    size_t size = sizeof(struct cDblDblRetDbl) + CODE_SIZE;
    /* valloc is nonstandard but we need an area aligned to a
     * page boundary for mprotect.
     */
    struct cDblDblRetDbl *result = valloc(size);
    result->function = function;
    result->a = a;
    /* Copy the code of the helper function into the structure.
     * Once again, we're casting a function pointer to an
     * object pointer and the standard doesn't say you can do that. 
     */
    memcpy(result->code, (void *) helper, CODE_SIZE);
    /* Memory protection is out of the scope of the standard,
     * and in a real program we need to check the return value.
     */
    mprotect(result, CODE_SIZE, PROT_READ | PROT_EXEC | PROT_WRITE);
    /* Casting an object pointer to a function pointer is also
     * not provided by the standard.
     * This example leaks memory.
     */
    return (double(*)(double)) result->code;
}

int main()
{
    call(bar);
    call(curryDoubleDoubleReturningDouble(func, 5));
    call(curryDoubleDoubleReturningDouble(func, 7));
    call(curryDoubleDoubleReturningDouble(func, 42.9));
}

If you wrote helper in assembly and created OS-specific versions of curryDoubleDoubleReturningDouble, you could probably get this working a lot of places. But I'm sure there are some computers C runs on where you can't do this.

Samuel Edwin Ward
  • 6,526
  • 3
  • 34
  • 62
  • 1
    It is legal to convert a function pointer of one type to a function pointer of any other type and back again, as long as you don't try to call it from the converted type, so you can use any type of function pointer as a kind of `void *`. You would have to convert it to the correct type before calling it, though, so you'd have to store information somewhere to do that (perhaps through another parameter for that purpose), so it's not all that elegant of a solution. – Crowman May 24 '14 at 22:38
  • `jmpbuf` is defined as an array type, so you can't move its value with assignments. But you *can* `memcpy` it. – luser droog May 25 '14 at 06:00
  • @PaulGriffiths, that's true, but it doesn't get you a new function pointer, I don't think. – Samuel Edwin Ward May 25 '14 at 12:06
  • @luserdroog, OK, but where am I going to put it? And why not skip the middleman and put the `double` there? – Samuel Edwin Ward May 25 '14 at 12:08
0

I think your example under Use GCC extension for functions in function is a viable solution. And incidentally, it is not an example of a GCC extension, but simply a helper function.

double inner(double x) {
    return func(x, 100);
}

That's perfectly valid C89.

luser droog
  • 18,988
  • 3
  • 53
  • 105
  • Of course, the downside is you have to create a separate version of `inner` in your source code for each value of `z`. – Samuel Edwin Ward May 25 '14 at 14:39
  • Sure, but I wanted to generate a new function for a lot of different `z`. I updated the question accordingly. – Martin Ueding May 26 '14 at 11:29
  • Also the downside now is that GCC stopped support of this feature and one PhD student's code relies on it; forcing him to stay at an older GCC version until the end of his thesis. – Martin Ueding Mar 25 '18 at 14:54