具有可变输入的函数指针

时间:2014-08-08 21:19:33

标签: c function-pointers

在C中,我试图将单变量函数传递给优化例程(optimization_routine)。优化例程将指针func1ptr作为输入作为单个float变量的函数。但是,我需要能够将多个变量传递给此函数。因此,我试图构造一个变量的函数指针,其中除了第一个输入之外的所有变量都是"常量"进入函数变量(类似于微积分中的偏导数)。我想我可以用函数指针做到这一点,但我无法弄清楚有意义的语法。

也就是说,我有这样的功能:

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

优化函数需要这样的指针:

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

因此,我想构建一个这种形式的函数:

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

fp指向的函数应该有签名:

float function_one_input(float A);

输入B,C和D在代码的其他地方计算,因此在编译时是未知的;但是,它们在optimization_function内是恒定的。

我想我可以使用函数指针在纯C中执行此操作,但是,我无法找出正确的语法。我在网上找到的所有例子都不包括这种情况。您可以提供任何建议。

4 个答案:

答案 0 :(得分:4)

听起来你问如何create a closure在C中捕捉参数,你可以看一下链接问题中的一些选项。

但是,如果没有自定义扩展,我认为您需要使用全局变量来实现您正在寻找的效果。

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

答案 1 :(得分:0)

你需要编写一个包装函数,比如

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

考虑并发性是一种重新入侵:

如果多个线程可以使用包装器,并且需要它来传递不同的数据,那么将这些全局线程设置为本地线程:

_Thread_local int b;

如果你需要完全重新入职,事情会变得复杂:

在使用具有不同参数的嵌套调用之前,您还需要(也)保存变量 使用不同的全局变量编写包装器的第二个(也许是第三个)版本可能会更好。

如果你需要同时更活跃,你可以尝试这些功能的池,虽然它很快就变得笨拙。通过添加context-parameter更好地更改优化函数,并使用该参数传递这些额外参数。

为了完全自由,你真的需要一种在运行时编写函数的方法,至少足以恢复上下文指针。但这在纯C中是不可能的。

答案 2 :(得分:0)

如果您的平台上有sizeof(float) >= sizeof(void*),那么您可以按照以下方式“破解”它:

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

关于返回值类型的问题,你不是很一致,所以我使用了int

答案 3 :(得分:0)

这可能有点矫枉过正,但libffi支持通过以下方式创建闭包:

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

}