簡體   English   中英

具有可變輸入的函數指針

[英]function pointer with variable inputs

在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中執行此操作,但是,我無法弄清楚正確的語法。 我在網上找到的所有例子都不包括這種情況。 您可以提供的任何建議將不勝感激。

聽起來你在問如何創建一個閉包來捕獲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);

你需要編寫一個包裝函數,比如

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中是不可能的。

如果您的平台上有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

這可能有點過分,但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;

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM