基于Matlab的嵌套结构

基于Matlab的嵌套结构,matlab,pointers,structure,loadlibrary,Matlab,Pointers,Structure,Loadlibrary,我将Matlab和C代码连接起来,以便能够直接使用Matlab中的一些C函数。我知道这些函数的原型,但是里面的代码可能会改变。 为了实现所有接口,我在Matlab中使用loadlibrary和calllib,我不想使用MexFile 在C代码中,定义了一些结构。尽管如此,定义代码基本组件的组件可能会发生变化:它包含一些结构和变量,但可以在其中添加一些其他结构,我希望Matlab能够处理所有这些 但是,正如Mathworks所说: 不支持嵌套结构或包含指向结构的指针的结构。但是,MATLAB可以访

我将Matlab和C代码连接起来,以便能够直接使用Matlab中的一些C函数。我知道这些函数的原型,但是里面的代码可能会改变。 为了实现所有接口,我在Matlab中使用loadlibrary和calllib,我不想使用MexFile

在C代码中,定义了一些结构。尽管如此,定义代码基本组件的组件可能会发生变化:它包含一些结构和变量,但可以在其中添加一些其他结构,我希望Matlab能够处理所有这些

但是,正如Mathworks所说:

不支持嵌套结构或包含指向结构的指针的结构。但是,MATLAB可以访问在外部库中创建的结构数组

所以我不能直接在Matlab中存储嵌套结构。例如,主要组件是一个结构(a)。这一个包含另一个结构(b)。和(b)包含指向函数的指针。 如果我使用libstruct将(a)直接存储在变量中,那么当我使用(a)in参数调用C方法时,我们可以看到指针丢失了。最糟糕的是,C代码知道指向结构(b)的指针是什么,但他无法访问指向的函数。 尽管如此,通过在Matlab中创建这个结构(b),它还是可以工作的,但是它是特定于(b)的,我不能对其他嵌套结构做同样的事情

这就是为什么我认为我必须阻止Matlab查看变量的类型。我只需要给它一个指向结构的指针,并锁定所有与这个指针相关的东西,这样就可以通过calllib在C函数的参数中传递这个指针

这就是我的问题:你知道我能否锁定一部分内存,其中包含结构(a)和所有与之相关的内容吗?你认为我能阻止Matlab看这个指针是什么吗

事实上,我只想在一个C函数中创建一个嵌套结构,并在另一个C函数中重用它,但要用Matlab调用这两个C函数(不使用MexFiles)

谢谢!:)

C代码

结构(a)

可在此结构(a)中添加其他结构

结构(b)

其中一个C功能的原型(第一个创建主组件的原型)

Matlab代码

调用函数fmi2安装并创建组件。

fmu.component=calllib(model, 'fmi2Instantiate', libpointer('int8Ptr', fmu.instanceName), fmu.type, libpointer('int8Ptr', fmu.guid), libpointer('int8Ptr', resourceLocation), fmu.callbackFunctions, visible, loggingOn);

此组件将进一步传入另一个C函数的参数。

从您的评论中可以看到不同的DLL,但导出的函数具有相同的原型,我无论如何会将库的管理委托给mex文件

请让我们考虑一个可以从Matlab中使用的<代码> fMIMANGER,MEX < /代码>:< /P>
[ok, msg] = FmiManager('SETUP', libraryName);
[hCallbacks] = FmiManager('CREATE_CALLBACKS', ... params for creating callbacks ...);
[hInstance] = FmiManager('CREATE_INSTANCE', hCallbacks, ... other params ...)
[...] = FmiManager('OTHER_COMMAND', ...);
这很简单,第一个参数是您想要对库执行的操作,其他参数是特定于您想要在c代码中调用的函数的

  • SETUP
    是一个额外的命令,用于动态更改链接的库
  • CREATE\u回调
    调用c函数来创建回调并返回回调句柄(例如,将指向“struct b”的c指针转换为int)
  • CREATE_INSTANCE
    调用c-function来实例化主组件,并将句柄返回到已创建的实例(例如,对于'struct a',再次简单转换为int),并将句柄作为回调的输入(只需在c-code中转换回'struct b'
  • OTHER_命令
    如果需要,您可以将该过程扩展到其他c函数
下面是一些伪代码,展示了如何构建这个
FmiManager.mex
文件:

[FmiManager.c]

#include <mex.h>
#include <windows.h>
#include "FmiManager.h" // The header for this mex file
#include "fmi.h" // The header for types in your 'fmi' library

// Pointer to correct dll
static HINSTANCE hDll = NULL;

// Pointer to the function that creates the callbacks
typedef fmi2CallbackFunctions* (FMI_CALLCONV createCallBacksPtr *)(...)
static createCallBacksPtr createCallBacks = NULL;

// Pointer to the function that performs instantiation
typedef fmi2Component* (FMI_CALLCONV instanciatePtr *)(...)
static instanciatePtr instanciate = NULL;

// Mex entry point
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Arguments parsing
    if (nrhs < 1) { mexErrMsgTxt("Not enough input arguments."); return; }
    if (!mxIsChar(prhs[0])) { mexErrMsgTxt("First parameter must be a string."); return; }

    // Command selection
    if (commandIs(prhs[0], "SETUP")) { processSetup(nlhs, plhs, nrhs, prhs); }
    else if (commandIs(prhs[0], "CREATE_CALLBACKS")) { processCreateCallbacks(nlhs, plhs, nrhs, prhs); }
    else if (commandIs(prhs[0], "INSTANCIATE")) { processInstanciate(nlhs, plhs, nrhs, prhs); }
    else { mexErrMsgTxt("Unknown command or command not implemented yet."); }
}

// Processing 'SETUP' command
void processSetup(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Free previous library
    if (hDll != NULL) { FreeLibrary(hDll); hDll = NULL; }

    // Load the new one
    char* librayPath = getThisMexPath();
    ... load library from '*prhs' (i.e. hDll = loadLibrary(fullpath))...
    mxFree(librayPath);

    // Bind functions pointers
    createCallBacks = (createCallBacksPtr)GetProcAddress(hDll, "createCallbacks");
    if (createCallBacks == NULL) { mexErrMsgTxt("Failed to map 'createCallBacks'"); return; }

    instanciate = (instanciatePtr)GetProcAddress(hDll, "instanciate");
    if (instanciate == NULL) { mexErrMsgTxt("Failed to map 'instanciate'"); return; }
}

// Processing 'CREATE_CALLBACKS' command
void processCreateCallbacks(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    ... unpack '*prhs' ...

    int hCallbacks = (int)createCallback(...); // Function has been binded during setup

    ... pack 'hCallbacks' into '*plhs' ...
}

// Processing 'INSTANCIATE' command
void processInstanciate(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    ... unpack '*prhs' ...

    int hInstance = (int)instanciate(...); // Function has been binded during setup

    ... pack 'hInstance' into '*plhs' ...
}

// Check if some command is really some givent one
bool commandIs(const mxArray* mxCommand, const char* command)
{
    double result;
    mxArray* plhs1[1];
    mxArray* prhs1[1];
    mxArray* plhs2[1];  
    mxArray* prhs2[2];

    if (mxCommand == NULL) { mexErrMsgTxt("'mxCommand' is null"); return false; }
    if (command == NULL) { mexErrMsgTxt("'command' is null"); return false; }
    if (!mxIsChar(mxCommand)) { mexErrMsgTxt("'mxCommand' is not a string"); return false; }

    // First trim
    prhs1[0] = (mxArray*)mxCommand;
    mexCallMATLAB(1, plhs1, 1, prhs1, "strtrim");

    // Then compare
    prhs2[0] = mxCreateString(command);
    prhs2[1] = plhs1[0];
    mexCallMATLAB(1, plhs2, 2, prhs2, "strcmpi");

    // Return comparison result
    result = mxGetScalar(plhs2[0]);  
    return (result != 0.0);
}

// Obtain the path of current mex file
// CAREFUL: Use mxFree on return pointer !!
char* getThisMexPath()
{
    mxArray *rhs[1], *lhs[1];
    char *path, *name;

    size_t lenpath, lenname, n;
    rhs[0] = mxCreateString("fullpath");
    mexCallMATLAB(1, lhs, 1, rhs, "mfilename");
    mxDestroyArray(rhs[0]);
    path = mxArrayToString(lhs[0]);
    mxDestroyArray(lhs[0]);

    mexCallMATLAB(1, lhs, 0, rhs, "mfilename");
    name = mxArrayToString(lhs[0]);
    mxDestroyArray(lhs[0]);

    lenpath = strlen(path);
    lenname = strlen(name);
    n = lenpath - lenname;
    path[n] = '\0';

    mxFree(name);

    return path; // Don't forget mxFree !!! 
}
[FmiManager.c]
#包括
#包括
#包括“FmiManager.h”//此mex文件的标题
#将“fmi.h”//fmi库中类型的标题包括在内
//指向正确dll的指针
静态HINSTANCE hDll=NULL;
//指向创建回调函数的指针
typedef fmi2CallbackFunctions*(FMI_CALLCONV createCallBacksPtr*)(…)
静态createCallBacksPtr createCallBacks=NULL;
//指向执行实例化的函数的指针
类型定义FMI2组件*(FMI_CALLCONV instanciatePtr*)(…)
静态instanciatePtr instanciate=NULL;
//Mex入口点
void MEX函数(int nlhs、mxArray*plhs[]、int nrhs、const mxArray*prhs[])
{
//参数解析
if(nrhs<1){mexerrmsgsgtxt(“输入参数不足”);return;}
if(!mxIsChar(prhs[0]){mexerrmsgsgtxt(“第一个参数必须是字符串”);return;}
//命令选择
if(commandIs(prhs[0],“SETUP”){processSetup(nlhs,plhs,nrhs,prhs);}
else if(commandIs(prhs[0],“CREATE_CALLBACKS”){processCreateCallbacks(nlhs,plhs,nrhs,prhs);}
else if(commandIs(prhs[0],“instanceate”){processinstanceate(nlhs,plhs,nrhs,prhs);}
else{mexErrMsgTxt(“未知命令或尚未实现的命令”);}
}
//正在处理“设置”命令
无效进程设置(int nlhs、mxArray*plhs[]、int nrhs、const mxArray*prhs[])
{
//免费以前的图书馆
如果(hDll!=NULL){freellibrary(hDll);hDll=NULL;}
//加载新的
char*librayPath=getThisMexPath();
…从'*prhs'加载库(即hDll=loadLibrary(完整路径))。。。
mxFree(librayPath);
//绑定函数指针
createCallBacks=(createCallBacksPtr)GetProcAddress(hDll,“createCallBacks”);
if(createCallBacks==NULL){mexerrmsgsgtxt(“映射'createCallBacks'失败”);return;}
instanciate=(instanciatePtr)GetProcAddress(hDll,“instanciate”);
if(instanciate==NULL){mexerrmsgsgtxt(“映射'instanciate'失败”);return;}
}
//正在处理“创建\u回调”命令
void processCreateCallbacks(int-nlhs,mxArray*plhs[],int-nrhs,const-mxArray*prhs[])
{
…打开“*prhs”。。。
int hCallbacks=(int)createCallback(…)/
fmu.component=calllib(model, 'fmi2Instantiate', libpointer('int8Ptr', fmu.instanceName), fmu.type, libpointer('int8Ptr', fmu.guid), libpointer('int8Ptr', resourceLocation), fmu.callbackFunctions, visible, loggingOn);
[ok, msg] = FmiManager('SETUP', libraryName);
[hCallbacks] = FmiManager('CREATE_CALLBACKS', ... params for creating callbacks ...);
[hInstance] = FmiManager('CREATE_INSTANCE', hCallbacks, ... other params ...)
[...] = FmiManager('OTHER_COMMAND', ...);
[FmiManager.c]

#include <mex.h>
#include <windows.h>
#include "FmiManager.h" // The header for this mex file
#include "fmi.h" // The header for types in your 'fmi' library

// Pointer to correct dll
static HINSTANCE hDll = NULL;

// Pointer to the function that creates the callbacks
typedef fmi2CallbackFunctions* (FMI_CALLCONV createCallBacksPtr *)(...)
static createCallBacksPtr createCallBacks = NULL;

// Pointer to the function that performs instantiation
typedef fmi2Component* (FMI_CALLCONV instanciatePtr *)(...)
static instanciatePtr instanciate = NULL;

// Mex entry point
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Arguments parsing
    if (nrhs < 1) { mexErrMsgTxt("Not enough input arguments."); return; }
    if (!mxIsChar(prhs[0])) { mexErrMsgTxt("First parameter must be a string."); return; }

    // Command selection
    if (commandIs(prhs[0], "SETUP")) { processSetup(nlhs, plhs, nrhs, prhs); }
    else if (commandIs(prhs[0], "CREATE_CALLBACKS")) { processCreateCallbacks(nlhs, plhs, nrhs, prhs); }
    else if (commandIs(prhs[0], "INSTANCIATE")) { processInstanciate(nlhs, plhs, nrhs, prhs); }
    else { mexErrMsgTxt("Unknown command or command not implemented yet."); }
}

// Processing 'SETUP' command
void processSetup(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Free previous library
    if (hDll != NULL) { FreeLibrary(hDll); hDll = NULL; }

    // Load the new one
    char* librayPath = getThisMexPath();
    ... load library from '*prhs' (i.e. hDll = loadLibrary(fullpath))...
    mxFree(librayPath);

    // Bind functions pointers
    createCallBacks = (createCallBacksPtr)GetProcAddress(hDll, "createCallbacks");
    if (createCallBacks == NULL) { mexErrMsgTxt("Failed to map 'createCallBacks'"); return; }

    instanciate = (instanciatePtr)GetProcAddress(hDll, "instanciate");
    if (instanciate == NULL) { mexErrMsgTxt("Failed to map 'instanciate'"); return; }
}

// Processing 'CREATE_CALLBACKS' command
void processCreateCallbacks(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    ... unpack '*prhs' ...

    int hCallbacks = (int)createCallback(...); // Function has been binded during setup

    ... pack 'hCallbacks' into '*plhs' ...
}

// Processing 'INSTANCIATE' command
void processInstanciate(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    ... unpack '*prhs' ...

    int hInstance = (int)instanciate(...); // Function has been binded during setup

    ... pack 'hInstance' into '*plhs' ...
}

// Check if some command is really some givent one
bool commandIs(const mxArray* mxCommand, const char* command)
{
    double result;
    mxArray* plhs1[1];
    mxArray* prhs1[1];
    mxArray* plhs2[1];  
    mxArray* prhs2[2];

    if (mxCommand == NULL) { mexErrMsgTxt("'mxCommand' is null"); return false; }
    if (command == NULL) { mexErrMsgTxt("'command' is null"); return false; }
    if (!mxIsChar(mxCommand)) { mexErrMsgTxt("'mxCommand' is not a string"); return false; }

    // First trim
    prhs1[0] = (mxArray*)mxCommand;
    mexCallMATLAB(1, plhs1, 1, prhs1, "strtrim");

    // Then compare
    prhs2[0] = mxCreateString(command);
    prhs2[1] = plhs1[0];
    mexCallMATLAB(1, plhs2, 2, prhs2, "strcmpi");

    // Return comparison result
    result = mxGetScalar(plhs2[0]);  
    return (result != 0.0);
}

// Obtain the path of current mex file
// CAREFUL: Use mxFree on return pointer !!
char* getThisMexPath()
{
    mxArray *rhs[1], *lhs[1];
    char *path, *name;

    size_t lenpath, lenname, n;
    rhs[0] = mxCreateString("fullpath");
    mexCallMATLAB(1, lhs, 1, rhs, "mfilename");
    mxDestroyArray(rhs[0]);
    path = mxArrayToString(lhs[0]);
    mxDestroyArray(lhs[0]);

    mexCallMATLAB(1, lhs, 0, rhs, "mfilename");
    name = mxArrayToString(lhs[0]);
    mxDestroyArray(lhs[0]);

    lenpath = strlen(path);
    lenname = strlen(name);
    n = lenpath - lenname;
    path[n] = '\0';

    mxFree(name);

    return path; // Don't forget mxFree !!! 
}