1

最亲爱的堆栈交换,

我正在编写核磁共振扫描仪。我不会过多介绍背景知识,但我在可以访问多少代码方面受到了相当大的限制,而且事情的设置方式……不是最理想的。我的情况如下:

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

简而言之,我的问题是:

  • 在一个方法的中间,在一个大块的数千行代码的一个很深的黑暗角落里,我几乎无法控制,天知道发生了什么变量范围,我需要:
    • 扩展此方法以将函数指针(指向用户空间函数)作为参数,但是
    • 让这个在库编译后编写的用户空间函数可以访问它出现的方法范围的本地变量,以及调用它的 (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();

占位符函数的要点是,如果用户函数没有链接进来,就让事情继续下去。我知道这可以用 a 代替#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 系统。

*顺便说一句,这是制造商用来阻止我们首先修改大库的主要理由!

4

1 回答 1

3

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

要求之一是“用户空间函数应该可以从调用它的 C 代码访问局部变量”。当您调用“某物”时,您只是给出了“doUseFullThings”的地址。没有“某物”的参数/参数可以捕获局部变量的地址。所以“doUseFullThings”无法访问这些变量。

malloc 语句返回指针。这没有得到妥善处理。(可能你试图给我们概述)。您必须注意在某个地方释放它。

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

于 2013-09-04T14:21:09.370 回答