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);
double OP_Addition(double (*f)(double,double) , double (*g)(double,double), double param1, double param2, double x);
z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
void *OP_PAdd( double (*f)(double,double), double param3 );
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 of some external library). You might use some JIT compiling library such as GNU lightning, libjit (both would generate quickly some slow-running code), asmjit (you'll generate each machine instruction explicitly, and it is your responsability 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 is the actual application you are coding, but you might consider embedding inside it some interpreter, e.g. Lua or Guile. You'll then use and/or provide callbacks to the embedded evaluator/interpreter.