Function pointer with variable inputs

In C, I am trying to pass a function with one variable to an optimization ( optimization_routine

) program . The optimization routine takes a func1ptr

function of one variable as an input pointer float

. However, I need to pass multiple variables to this function. So I'm trying to construct a pointer to a single variable where all but the first inputs are "constants" in the function variable (sort of analogous to a partial derivative in calculus). I think I can do it with function pointers, but I cannot figure out the syntax that makes sense.

That is, I have a function like this:

float function_all_inputs( float A, int B, float C, char D);

      

The optimization function requires a pointer like this:

typedef (*func1ptr)(float);
void optimization_function( func1ptr fp );

      

Thus, I want to build a function of this form:

// create a function of A only at runtime using inputs B,C,D
func1ptr fp = ( & function_all_inputs(A,B,C,D))(A);  

      

The function it points fp

to must be signed:

float function_one_input(float A);

      

Inputs B, C, and D are evaluated elsewhere in the code and are thus not known at compile time; however, they are permanent inside optimization_function

.

I think I can do this in pure C using function pointers, however I cannot figure out the correct syntax. None of the examples I've found on the internet cover this case. Any advice you can provide would be appreciated.

+3


source to share


4 answers


It sounds like you are asking how to create a parameter capturing closure in C, and you can look at some options in the linked question.

However, without custom extensions, I think you will need to use globals to achieve the effect you are looking for.



// Pass this wrapper with the name "wrapper" into the function 
// that requires a function pointer
void wrapper(float a) {
    // Where last four arguments are global variables that are computed first.
    function_all_inputs(a, b, c, d, e); 
}

// No need to create an explicit function pointer. 
// Passing the name of the function is sufficient.
optimization_function(wrapper);

      

+3


source


You need to write a wrapper function like

int b;
float c;
char d;
int wrap(float a) {
    return function_all_inputs(a, b, c, d);
}

      

Consider concurrency re-inclusion:

If multiple threads can use the wrapper and need to transfer different data, make these global threads local:

_Thread_local int b;

      



If you want a full redirect, things get complicated:

You need to (also) save the variables before using the nested call with different parameters.
Writing a second (and possibly third) version of the wrapper using different globals might be better.

If you need to be more active at the same time, you can try pooling these functions, although it quickly becomes cumbersome. Better change your optimization function by adding a context parameter and passing these additional parameters.

For complete freedom, you really need a way to write functions at runtime, at least to restore the context pointer. This is not possible in pure C, though.

0


source


If sizeof(float) >= sizeof(void*)

on your platform, you can "hack" it like this:

typedef struct
{
    float a;
    int   b;
    float c;
    char  d;
}
params;

int function_all_inputs(float a, int b, float c, char d)
{
    ...
}

int function_one_input(float f)
{
    params* p;
    memcpy((void*)&p, (void*)&f, sizeof(void*));
    return function_all_inputs(p->a, p->b, p->c, p->d); 
}

int optimize()
{
    float   f;
    params  v;
    params* p = &v;

    v.a = ...;
    v.b = ...;
    v.c = ...;
    v.d = ...;

    memcpy((void*)&f, (void*)&p, sizeof(void*));
    return optimization_function(function_one_input, f);
}

      

You don't really agree on the return type, so I used int

.

0


source


It might be overkill, but libffi supports creating closures like this:

#include <stdio.h>
#include <ffi.h>

typedef struct BCD { int B; float C; char D; } BCD;

void function_one_input_binding
  (ffi_cif* cif, int* result, void** args, BCD* bcd) {
  *result = function_all_inputs(*(float*)args[0], bcd->B, bcd->C, bcd->D);
}

int main() {

  ffi_cif cif;
  ffi_type* args[1];
  ffi_closure* closure;

  int (*function_one_input)(float);

  // Allocate a closure.
  closure = ffi_closure_alloc(sizeof(ffi_closure), &function_one_input);

  // Tell libffi the parameter and return types.
  args[0] = &ffi_type_float;
  ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_int, args);

  // Bind closure data.
  BCD bcd = { .B = 1, .C = 2.5, .D = 'x' };
  ffi_prep_closure_loc(
    closure, &cif, function_one_input_binding, &bcd, function_one_input);

  // Call the function.
  int result = function_one_input(42.5);

  // Free the allocated closure.
  ffi_closure_free(closure);

  return 0;

}

      

0


source







All Articles