我发现了一个非常棘手的问题,我似乎无法轻易解决这个问题 . 简而言之,我想从一个mex文件返回一个数组,该数组已作为mex函数输入传递 . 你可以琐碎地做到这一点:
void mexFunction(int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin[])
{
pargout[0] = pargin[0];
}
但这不是我需要的 . 我想从 pargin[0]
获取原始指针,在内部处理它,并通过设置相应的数据指针返回一个新创建的mex数组 . 像那样:
#include <mex.h>
void mexFunction(int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin[])
{
mxArray *outp;
double *data;
int m, n;
/* get input array */
data = mxGetData(pargin[0]);
m = mxGetM(pargin[0]);
n = mxGetN(pargin[0]);
/* copy pointer to output array */
outp = mxCreateNumericMatrix(0,0,mxDOUBLE_CLASS,mxREAL);
mxSetM(outp, m);
mxSetN(outp, n);
mxSetData(outp, data);
/* segfaults with or without the below line */
mexMakeMemoryPersistent(data);
pargout[0] = outp;
}
它不起作用 . 我得到一个段错误,如果没有立即,然后几个电话后 . 我相信没有关于这种情况的说法in the documentation . 唯一的要求是 data
指针已经使用 mxCalloc
分配,显然它有 . 因此,我认为这段代码是合法的 .
我需要这样做,因为我正在将一个复杂的MATLAB结构解析为我的内部C数据结构 . 我处理数据,一些数据被重新分配,有些则没有 . 我想透明地返回输出结构,而不必考虑何时只需复制 mxArray
(第一个代码片段),以及何时我必须创建它 .
请帮忙!
EDIT
在进一步查看和讨论Amro后,似乎我的第一个代码片段不受支持,并且在某些情况下会导致MATLAB崩溃,例如,在将结构字段或单元格元素传递给此类mex函数时:
>> a.field = [1 2 3];
>> b = pargin_to_pargout(a.field); % ok - works and assigns [1 2 3] to b
>> pargin_to_pargout(a.field); % bad - segfault
看来我必须沿着'undocumented MATLAB'路走下去并使用 mxCreateSharedDataCopy
和 mxUnshareArray
.
2 回答
你应该使用mxDuplicateArray,这就是记录的方式:
虽然没有记录,但MEX API函数
mxCreateSharedDataCopy
现在显然被拒绝,用于创建mxArray
的共享数据副本 . MathWorks甚至在他们的解决方案中提供了一个示例,mxsharedcopy.c .如删除的MathWorks解决方案(1-6NU359)中所述,该函数可用于克隆
mxArray
标头 . 但是,执行plhs[0] = prhs[0];
和plhs[0] = mxCreateSharedDataCopy(prhs[0]);
之间的区别在于第一个版本只是复制mxArray*
(一个指针),因此不会创建一个新的mxArray
容器(至少在mexFunction
返回之前并且MATLAB在mxArray
中使用's magic), which would increment the data'的引用计数秒 .为什么这可能是一个问题?如果您使用
plhs[0] = prhs[0];
并且在从mexFunction
返回之前不对plhs[0]
进行进一步修改,那么一切都很好,并且由于MATLAB,您将拥有共享数据副本 . 但是,如果在上述赋值之后修改了MEX函数中的plhs[0]
,则在prhs[0]
中也会看到更改,因为它引用了相同的数据缓冲区 . 另一方面,当显式生成共享副本(使用mxCreateSharedDataCopy
)时,有两个不同的mxArray
对象,对一个数组的数据的更改将触发复制操作,从而产生两个完全独立的数组 . 另外,直接分配can cause segmentation faults in some cases .修改了MathWorks示例
从上面引用的MathWorks解决方案中使用修改后的
mxsharedcopy.c
开始 . 第一个重要步骤是为mxCreateSharedDataCopy
函数提供原型:正如评论所述,这不是
mex.h
,所以你必须自己声明 .mxsharedcopy.c
的下一部分通过以下方式创建新的mxArray
:mxDuplicateArray
进行深层复制:mxCreateSharedDataCopy
共享副本:mxArray*
的直接副本,由我添加:然后它为每个
mxArray
打印数据缓冲区的地址(pr
)及其第一个值 . 以下是x=ones(1e3);
修改mxsharedcopy(x)
的输出:发生了什么:
正如预期的那样,比较
prhs[0]
和copy0
我们没有创建任何新的东西,除了指向同一个mxArray
的另一个指针 .比较
prhs[0]
和copy1
,注意mxDuplicateArray
在地址721BF120
处创建了新的mxArray
,并将数据复制到19740060
的新缓冲区中 .copy2
与copy1
具有不同的地址(mxArray*
),这意味着它也是一个不同的mxArray
,而不仅仅是不同变量指向的相同地址,而 they both share the same data 在地址19740060
处 .问题简化为:在
copy0
或copy2
(分别来自简单指针复制或mxCreateSharedDataCopy
)的plhs[0]
中返回是否安全,或者是否必须使用实际复制数据的mxDuplicateArray
?我们可以证明mxCreateSharedDataCopy
可以通过破坏copy1
并验证copy2
仍然有效有效:将共享数据复制应用于输入
回到问题 . 比MathWorks示例更进一步,返回输入的共享数据副本 . 做就是了:
屏住呼吸!
现在进行临时输入(没有
format debug
):有趣的是,如果我在没有
mxCreateSharedDataCopy
的情况下进行测试(即仅使用plhs[0] = prhs[0];
),MATLAB不会崩溃,但输出变量永远不会实现:R2013b,Windows,64位 .
mxsharedcopy.cpp (modified C++ version):