将函数指针作为API接口传递到已编译的库
Passing function pointers as an API interface to a compiled library
最静止堆栈交换,
我正在为核磁共振扫描仪编程。我不会深入太多的背景,但我在访问多少代码方面受到了相当大的限制,而且设置的方式……不太理想。我的情况如下:
- 有一个用C++编写的大型库。它最终进行"代码转换"(以最糟糕的方式),写出完成任务的FPGA组件。它为"userland"提供了一组函数,这些函数被翻译成(通过预处理器宏和黑魔法的混合)16位和32位单词的长字符串。这样做的方式很容易发生缓冲区溢出,而且通常会发生溢出*
- 然后,FPGA组件通过一个光荣的串行链路连接到相关的电子设备,电子设备执行它(进行扫描),并再次返回数据进行处理
- 程序员应该使用库提供的函数来完成他们的工作,在与标准库链接的C(而不是C++)函数中。不幸的是,就我而言,我需要扩建图书馆
- 在你在代码中写doSomething()和相关的库函数实际执行它之间,有一个相当复杂的预处理器替换和标记化、调用和(通常)的事情发生的链。我想我在某种程度上已经弄清楚了,但这基本上意味着我对任何东西的范围都没有真正的了解
简而言之,我的问题是:
- 在一个方法的中间,在一个大斑点中成千上万行代码的黑暗角落里,我几乎无法控制,随着god-knows-what variable scopeing的进行,我需要:
-
- 将此方法扩展为将函数指针(指向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系统。
*顺便说一句,这是制造商最初阻止我们修改大型库的主要理由!
您可以完全访问C代码。您对C++库代码的访问权限有限。C代码定义了"doUsefullthings"函数。从C代码调用"Something"函数(C++类/函数),函数指针指向"doUseFullThings"作为参数。现在控件转到C++库。在这里,各种参数被分配内存并初始化。然后使用这些参数调用"doUseFullThings"。在这里,控制权转移回C代码。简而言之,主程序(C)调用库(C++),库调用C函数。
其中一个要求是"userland函数应该可以从调用它的C代码访问本地变量"。当你调用"某物"时,你只给出了"doUseFullThings"的地址。没有"something"的参数/自变量可以捕获局部变量的地址。因此"doUseFullThings"无法访问这些变量。
malloc语句返回指针。这件事没有得到妥善处理。(可能你是想给我们概述一下)。你一定要小心把它放在某个地方。
由于这是C和C++代码的混合体,因此很难使用RAII(处理分配的内存)、完美转发(避免复制变量)、Lambda函数(访问本地变量包)等。在这种情况下,您的方法似乎是可行的。
- 二叉排序树无法编译
- 编译时未启用intel oneApi CUDA支持
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- CMake:替换接口目标的编译标志
- 与C 一起编译和链接卷曲简易接口
- 是否有任何挂钩接口在编译时间内更换功能
- 在编译时使用运行时接口
- 使用 ATL 编译 dll,并将方法参数作为接口,但将它们作为 coclass 获取
- 编译C++使用SWI-Prolog接口的程序
- 编译错误外部接口Simulink
- 将函数指针作为API接口传递到已编译的库
- 编译时检查基类是否为"接口"
- 编译时接口定义的最佳实践
- 编译错误:找不到标头、类和类接口的任何问题
- 编译DLL中指定的接口
- 切换到c++ 11时,是否需要重新编译所有在接口中使用STL的依赖库?
- 如果接口的头改变,为什么需要重新编译接口的客户端
- C++编译时使用接口的鸭子打字
- 如何编译仅在头文件中的C++接口
- 可以在不重新编译客户端代码的情况下扩展虚拟接口吗?