MCL
MCL

Reputation: 566

How can I make a function that returns a function?

Big picture: I have a module with functions and a module with procedures and functions over those functions.

When I combine two functions (from function's module interface):

double f1(double alpha, double x);
double f2(double beta, double x);

In several ways, (one of them is adding):

double OP_Addition(double (*f)(double,double) , double (*g)(double,double), double param1, double param2, double x);

Gives no problem with the following (piece of) implementation:

z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
return y;

But when I want to return a pointer to a "new" function, something like:

void *OP_PAdd( double (*f)(double,double), double param3 );

I can not get it to work properly, neither make the right "call". I want to have use the output "function" as input in other functions.

Upvotes: 39

Views: 2777

Answers (7)

Other answers are correct and interesting, but you should be aware that in portable C99, there is no way to have genuine closures as C functions (and this is a fundamental limitation of C). If you are not aware of what closures are, read the wiki page carefully on them (and also read SICP, notably its §1.3). Notice however that in C++11 you do have closures, using std::function and lambda-expressions. And most other programming languages (Ocaml, Haskell, Javascript, Lisp, Clojure, Python, ....) have closures.

Because of the lack of genuine closures in C ("mathematically" the only closed values in C functions are global or static variables or literals), most libraries accepting C function pointers provide an API handling callbacks with some client data (a simple example could be qsort_r, but more seriously look inside GTK). That client data (generally an opaque pointer) can be used to keep closed values. You probably want to follow a similar convention (so systematically pass function pointer as callbacks with some additional client data), so you'll need to change the signatures of your C functions (instead of passing just a raw function pointer, you'll pass both a function pointer and some client data as a callback, to "emulate" closures).

You could sometimes generate a C function at runtime (using non-standard features, probably with the help of the operating system or some external library). You might use some JIT compiling library such as GNU lightning, libjit (both would generate some slow-running code quickly), asmjit (you'll generate each machine instruction explicitly, and it is your responsibility to emit fast x86-64 code), GCCJIT or LLVM (both are above existing compilers so can be used to emit -a bit slowly- some optimized code). On POSIX & Linux systems, you could also emit some C code in some temporary file /tmp/tempcode.c, fork a compilation (e.g. gcc -fPIC -Wall -O2 -shared /tmp/tempcode.c -o /tmp/tempcode.so) of that code into a plugin, and dynamically load that generated plugin using dlopen(3) & dlsym(3)..

BTW we don't know what the actual application you are coding is, but you might consider embedding inside it some interpreter, e.g. Lua or Guile. You'll then use and provide callbacks to the embedded evaluator/interpreter.

Upvotes: 25

DeftlyHacked
DeftlyHacked

Reputation: 405

Since some people are apparently paranoid about writing a hack to solve this problem, here's a less-hacky way to do it: Use a static struct with setjmp and longjmp.

jmp_buf jb;

void *myfunc(void) {
    static struct {
        // put all of your local variables here.
        void *new_data, *data;
        int i;
    } *_;
    _ = malloc(sizeof(*_));
    _.data = _;
    if (!(_.new_data = (void *)(intptr_t)setjmp(jb)))
        return _.data;
    _.data = _.new_data;
    /* put your code here */
    free(_);
    return NULL;
}

To explain what's going on here, setjmp will return a value of 0 when the jump buffer is created, otherwise it'll return the value passed by longjmp (eg. longjmp(jb, 5) will cause setjmp to return 5).

So, what we're doing is having our function return a pointer to it's allocated data structure; and then calling our closure like:

void *data = myfunc();
longjmp(jb, (int)(intptr_t)data);

Please note that an int is not guaranteed to be large enough to store a pointer on all platforms; so you may need to create a data pool and return/pass the data by handle (index in the pool).

As I've stated before, a closure is just a function with all of it's data allocated on the heap.

I've been writing hacks for N64 and PSP games for years. People claiming that this is impossible have likely never tinkered with that kind of stuff. Mostly just boils down to a lack of experience.

Upvotes: 0

Bing Bang
Bing Bang

Reputation: 544

So you want a function to return a pointer to a function.

double retfunc()
{
   return 0.5;
}

double (*fucnt)()
{
  return retfunc;
}

main()
{
   printf("%f\n", (*funct())());
}

Upvotes: 0

DeftlyHacked
DeftlyHacked

Reputation: 405

I'm gonna get really hacky here, so hold on to your breeches.

The standard C api comes with a 2 functions called setjmp and longjmp. Poor naming aside, what they essentially do is store a copy of the current state (including the stack position and register values) into a jmp_buf (or, the technical name, a continuation).

Now, lets say you create a function:

jmp_buf jb;

void sfunc(void) {
    void *sp_minus1 = 0xBEEFBABE;
    setjmp(jb);
}

When you call sfunc, a stack frame will be created. Because there are no arguments to this function, the first entry in the stack will be the return address and immediately after it will be the sp_minus1 object.

Why is this relevant? Well, the address of sp_minus1 is relative to the start of the stack frame. If you can find the address of the stack frame in jb, you can change it...say, to a location in the heap?

What we've got at this point is a way to create stack frames for longjmp function calls on the heap that can contain additional state about the context in which they were called; or in other words, closures.

I don't think I've ever seen anyone use longjmp/setjmp this way, but if you're looking for a way to dynamically generate and return functions in C, I think this would be your best route.

EDIT:

Here's an example implementation of the hack I'm describing:

#include <inttypes.h>  // intptr_t
#include <setjmp.h>    // longjmp, setjmp
#include <stdio.h>     // printf
#include <stdlib.h>    // malloc, free
#include <string.h>    // memcpy


typedef struct {
    jmp_buf jb;
    int fixupc;
    int fixupv[10];
    size_t stack_size;  // this is only an approximation
    void *stack_ptr;
} CLOSURE;


int getclosure(CLOSURE *closure) {
    unsigned int i, size;
    void *i_ptr = &i, *sp;
    unsigned char *data = (unsigned char *)(void *)closure->jb;
    memset(closure, 0, sizeof(CLOSURE));
    if (!setjmp(closure->jb)) {
        printf("looking for 0x%08X...\n\n", (unsigned int)(intptr_t)i_ptr);
        for (i = 0; i < sizeof(closure->jb); i++) {
            memcpy(&sp, &data[i], sizeof(void *));
            size = (unsigned int)(intptr_t)(sp - i_ptr);
            if (size < 0x300) {
                closure->fixupv[closure->fixupc++] = i;
                printf("  fixup @ 0x%08X\n", (unsigned int)(intptr_t)sp);
                if (sp > closure->stack_ptr) {
                    closure->stack_size = size;
                    closure->stack_ptr = sp;
                }
            }
        }
        if (!closure->stack_ptr)
            return 0;
        printf("\nsp @ 0x%08X\n", (unsigned int)(intptr_t)closure->stack_ptr);
        printf("# of fixups = %i\n", closure->fixupc);
        /*
         * once we allocate the new stack on the heap, we'll need to fixup
         * any additional stack references and memcpy the current stack.
         *
         * for the sake of this example, I'm only fixing up the pointer
         * to the stack itself.
         *
         * after that, we would have successfully created a closure...
         */
         closure->stack_size = 1024;
         sp = malloc(closure->stack_size);
         memcpy(sp, closure->stack_ptr, closure->stack_size);
         memcpy(&data[closure->fixupv[0]], &sp, sizeof(void *));
         closure->stack_ptr = sp;
         return 1;
    } else {
        /*
         * to this bit of code right here
         */
        printf("holy shit!\n");
        return 0;
    };
}

void newfunc(CLOSURE *closure) {
    longjmp(closure->jb, 1);
}

void superfunc(CLOSURE *closure) {
    newfunc(closure);
}

int main(int argc, char *argv[]) {
    CLOSURE c;
    if (getclosure(&c)) {
        printf("\nsuccess!\n");
        superfunc(&c);
        free(c.stack_ptr);
        return 0;
    }
    return 0;
}

This is technically a form of stack smashing, so by default, GCC will generate stack canaries that cause the program to abort. If you compile with '-fno-stack-protection', it'll work.

Upvotes: -1

dbush
dbush

Reputation: 223972

When returning a function from another function, the cleanest way to do this is with a typedef:

typedef double (*ftype)(double, double);

Then you can declare your function like this:

ftype OP_PAdd( ftype f, double param3 )
{
    ....
    return f1;
}

You can do this without a typedef, but it's messy:

double (*OP_PAdd( double (*f)(double,double), double param3 ))(double,double)
{
    return f1;
}

So when you have function pointers as either parameters or return values of other functions, use a typedef.

EDIT:

While you could declare the type like this:

typedef double ftype(double, double);

You can never directly use a type like this in practice. A function can't return a function (only a pointer to a function), and a variable of this type can't be assigned to.

Also, you don't need to explicitly dereference a function pointer to call the function, so the fact that the pointer itself is hidden is not a big issue. It's also convention to define function pointers as a typedef. From the man page for signal:

   #include <signal.h>

   typedef void (*sighandler_t)(int);

   sighandler_t signal(int signum, sighandler_t handler);

Upvotes: 32

Jordan Szubert
Jordan Szubert

Reputation: 176

in C, you can return pointer to function, but to do that, function needs to exist first, and dynamically creating functions is not something C says is possible, never mind how to do it

if your code is going to work only on one OS and one processor (and probably some other restrictions), you may be able to:

  1. allocate page of memory
  2. write data and machine code doing what you want, calling functions passed by pointer etc.
  3. change memory protection from read/write to read/execute
  4. return pointer to created function
  5. don't worry that you you need 4kB per function

there probably are somewhere libraries for that, but necessarily not portable

Upvotes: 3

Weather Vane
Weather Vane

Reputation: 34585

Do you mean something like this? The decider() function returns a pointer to another function, which is then called.

#include <stdio.h>
#include <stdlib.h>

typedef double(*fun)(double, double);

double add(double a, double b) {
    return a + b;
}

double sub(double a, double b) {
    return a - b;
}

double mul(double a, double b) {
    return a * b;
}

fun decider(char op) {
    switch(op) {
        case '+': return add;
        case '-': return sub;
        case '*': return mul;
    }
    exit(1);
}

int main(void)
{
    fun foo;

    foo = decider('+');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('-');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('*');
    printf("%f\n", foo(42.0, 24.0));

    return 0;
}

Program output:

66.000000
18.000000
1008.000000

EDIT: Following comments under the @dbush answer, this version steps back from the typedef as a pointer, to just a function. It gives the same output, but in decider() it compiles cleanly and gives the correct output, no matter whether I write return add; or return &add;

#include <stdio.h>
#include <stdlib.h>

typedef double(fun)(double, double);

double add(double a, double b) {
    return a + b;
}

double sub(double a, double b) {
    return a - b;
}

double mul(double a, double b) {
    return a * b;
}

fun *decider(char op) {
    switch(op) {
        case '+': return add;     // return &add;
        case '-': return sub;
        case '*': return mul;
    }
    exit(1);
}

int main(void)
{
    fun *foo;

    foo = decider('+');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('-');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('*');
    printf("%f\n", foo(42.0, 24.0));

    return 0;
}

Upvotes: 13

Related Questions