将函数指针作为API接口传递给已编译的库

时间:2013-09-04 12:21:46

标签: c++ c function-pointers library-design

最近的堆栈交换,

我正在编写MRI扫描仪。我不会涉及太多的背景,但是我对我可以访问的代码数量相当受限,并且设置的方式是......不是最理想的。我的情况如下:

  • 有一个用C ++编写的大型库。它最终会进行“转码”(以最糟糕的方式),编写出DoThings的FPGA组件。它为“userland”提供了一组函数,这些函数被翻译成(通过混合预处理器宏和黑魔法)长字符串的16位和32位字。这样做的方式是容易出现缓冲区溢出,并且通常会崩溃。*
  • 然后将FPGA组件通过一个美化的串行链路连接到相关的电子设备,执行它(进行扫描),然后再将数据返回处理。
  • 程序员应该使用库提供的功能来完成与标准库链接的C(而不是C ++)函数。不幸的是,就我而言,我需要扩展库。
  • 在你的代码中编写doSomething()和实际执行它的相关库函数之间有一个相当复杂的预处理器替换和标记化链,调用和(通常)发生的事情。我想我已经在某种程度上弄明白了,但这基本上意味着我对任何东西的范围没有真正的了解......

简而言之,我的问题是:

  • 在一个方法的中间,在一个大blob中成千上万行代码的一个深黑暗的角落里我几乎无法控制,上帝知道什么变量范围正在进行,我需要:
    • 扩展此方法以将函数指针(作为userland函数)作为参数,但
    • 让这个在编译库之后编写的userland函数可以访问它所出现的方法范围内的变量,以及调用它的(C)函数中的变量。

这似乎是对内存管理的绝对泥潭,我想我会在这里问这些情况下的“最佳实践”,因为我可能遇到很多微妙的问题 - 而其他的可能有很多相关的智慧传授。调试系统是一场噩梦,我并没有真正得到扫描仪制造商的支持。

我计划如何进行的简要说明如下:

在.cpp库中:

/* In something::something() /*
/* declare a pointer to a function */
    void (*fp)(int*, int, int, ...);
/* by default, the pointer points to a placeholder at compile time*/
    fp = &doNothing(...);

...

/* At the appropriate time, point the pointer to the userland function, whose address is supplied as an argument to something(): /*
    fp= userFuncPtr;
/* Declare memory for the user function to plonk data into */ 
    i_arr_coefficients = (int) malloc(SOMETHING_SENSIBLE);
/* Create a pointer to that array for the userland function */ 
    i_ptr_array=&i_arr_coefficients[0];
/* define a struct of pointers to local variables for the userland function to use*/
 ptrStrct=createPtrStruct(); 

/* Call the user's function: */
fp(i_ptr_array,ptrStrct, ...);

CarryOnWithSomethingElse();

占位符函数的目的是在没有链接用户函数的情况下保持一致。我知道这可以用#DEFINE替换,但编译器的聪明或愚蠢可能导致奇数(对我无知的头脑,至少)行为。

在userland函数中,我们有类似的东西:

void doUsefulThings(i_ptr_array, ptrStrct, localVariableAddresses, ...) { 
    double a=*ptrStrct.a;
    double b=*ptrStrct.b;
    double c=*localVariableAddresses.c;
    double d=doMaths(a, b, c);
    /* I.e. do maths using all of these numbers we've got from the different sources */

    storeData(i_ptr_array, d);
    /* And put the results of that maths where the C++ method can see it */
}

...

something(&doUsefulThings(i_ptr_array, ptrStrct, localVariableAddresses, ...), ...); 

...

如果这个像泥一样清楚,请告诉我!非常感谢您的帮助。而且,顺便说一下,我真诚地希望有人能够制作一个开放的硬件/源MRI系统。

*另外,这是制造商用来阻止我们首先修改大型图书馆的主要理由!

1 个答案:

答案 0 :(得分:2)

您可以完全访问C代码。您对C ++库代码的访问权限有限。 C代码定义了“doUsefullthings”函数。从C代码中,您调用“Something”函数(C ++类/函数),函数指针以“doUseFullThings”作为参数。现在控件转到C ++库。这里各种参数都分配了内存并进行了初始化。然后用这些参数调用“doUseFullThings”。这里控件转回C代码。简而言之,主程序(C)调用库(C ++),库调用C函数。

其中一个要求是“userland函数应该可以从调用它的C代码访问本地变量”。当你打电话给“某事”时,你只给出“doUseFullThings”的地址。没有参数/参数“something”捕获局部变量的地址。因此“doUseFullThings”无法访问这些变量。

malloc语句返回指针。这没有得到妥善处理。(可能你试图给我们概述)。你必须小心翼翼地将它释放到某处。

由于这是C和C ++代码的混合,很难使用RAII(处理分配的内存),完美转发(避免复制变量),Lambda函数(访问本地varibales)等。在这种情况下,你的方法似乎是要走的路。