我正在mex
文件中编写一个调用MATLAB
函数的函数。不幸的是,当谈到mxSetPr
时,MATLAB
崩溃并且不会继续进行。有人可以告诉我如何解决这个问题吗?
void myconv2( double * Ain , double *Aout,
int AnRows , int AnCols,
double* kernel, int kernelnRows, int kernelnCols )
{
mxArray *rhs[3], *lhs[1];
rhs[0] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
rhs[1] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
rhs[2] = mxCreateString ( "same" );
mxSetPr( rhs[0], Ain );
mxSetM ( rhs[0], AnRows );
mxSetN ( rhs[0], AnCols );
mxSetPr( rhs[1], kernel );
mxSetM ( rhs[1], kernelnRows );
mxSetN ( rhs[1], kernelnCols );
mexCallMATLAB(1, lhs, 3, rhs, "conv2");
Aout = mxGetPr( lhs[0] );
}
答案 0 :(得分:2)
传递给mxSetPr
的内存必须分配mxMalloc
或mxCalloc
,而不是malloc
,new
等。来自{{3} }:
void mxSetPr(mxArray *pm, double *pr);
...
pr
指向数组第一个元素的指针。数组中的每个元素都包含值的实部。数组必须在动态内存中; 调用
mxCalloc
来分配此内存。不要使用ANSI®Ccalloc
函数,这会导致导致程序终止的内存对齐问题。如果pr
指向静态内存,则可能导致内存泄漏和其他内存错误。
另一个问题是您对myconv2
的声明,其中输出参数为double *Aout
。在函数内部,Aout
本身被修改,而不是Aout
最初指向的任何内容,如果有的话。要修改指针,要么通过引用传递(double *&Aout
),要么传递双指针(double **Aout
)并更改您的调用约定。如果您正在编译为C ++,则最容易使用引用。
这会让您超越mxSetPr
命令并允许您运行mexCallMATLAB
,但下一个问题是mxArray
指向的plhs[1]
已创建 inside myconv2
,这意味着它将在程序终止后由MATLAB内存管理器解除分配。您应该将数据从lhs[1]
复制到Aout
(我认为这是您想要的,因为您按值传递指针)或在Aout
之外分配myconv2
使用mxMalloc
或mxCalloc
。
让mxSetPr
与创建mxArray*
的函数不同的另一个有趣的惊喜是当myconv2
存在时,MATLAB也会尝试销毁每个mxArray
在rhs[]
中。假设您希望调用者对这些数组负责,然后在NULL
退出之前将指针设置为myconv2
。我以前从未遇到过这种情况,但这可能是一种有效的方法。
复制myconv
#include "mex.h"
void myconv2(double * Ain, double *Aout,
int AnRows, int AnCols,
double* kern, int kernelnRows, int kernelnCols)
{
mxArray *rhs[3], *lhs[1];
rhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
rhs[1] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
rhs[2] = mxCreateString("same");
mxSetPr(rhs[0], Ain);
mxSetM(rhs[0], AnRows);
mxSetN(rhs[0], AnCols);
mxSetPr(rhs[1], kern);
mxSetM(rhs[1], kernelnRows);
mxSetN(rhs[1], kernelnCols);
mexCallMATLAB(1, lhs, 3, rhs, "conv2");
// prevent `Ain` and `kern` from being destroyed on `myconv2` return
mxSetPr(rhs[0], NULL); mxSetPr(rhs[1], NULL);
// copy each element of output
double *d = mxGetPr(lhs[0]);
for (int i = 0; i < AnRows*AnCols; ++i)
Aout[i] = d[i];
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int nrows = 256, ncols = 256;
double *Aout = new double[nrows * ncols];
// allocate with `mxMalloc`
double *Ain = (double*)mxMalloc(nrows * ncols * sizeof(double));
double *kern = (double*)mxMalloc(5 * 5 * sizeof(double));
myconv2(Ain, Aout, nrows, ncols, kern, 5, 5);
// free here, not in `myconv2`
mxFree(Ain);
mxFree(kern);
// do something with Aout
mexPrintf("%p\n", Aout);
delete[] Aout;
}
在lhs
之外创建myconv2
以避免任何副本
void myconv2(double *Ain, mxArray *&lhs, int AnRows, int AnCols,
double *kern, int kernelnRows, int kernelnCols)
{
mxArray *rhs[3];
rhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
rhs[1] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
rhs[2] = mxCreateString("same");
mxSetPr(rhs[0], Ain);
mxSetM(rhs[0], AnRows);
mxSetN(rhs[0], AnCols);
mxSetPr(rhs[1], kern);
mxSetM(rhs[1], kernelnRows);
mxSetN(rhs[1], kernelnCols);
mexCallMATLAB(1, &lhs, 3, rhs, "conv2");
mxSetPr(rhs[0], NULL); mxSetPr(rhs[1], NULL);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mxArray *AoutMX;
int nrows = 256, ncols = 256;
double *Ain = (double*)mxMalloc(nrows * ncols * sizeof(double));
double *kern = (double*)mxMalloc(5 * 5 * sizeof(double));
myconv2(Ain, AoutMX, nrows, ncols, kern, 5, 5);
mxFree(Ain); mxFree(kern);
// do something with AoutMX
mexPrintf("%x\n", mxGetPr(AoutMX));
}
尽管如此,请务必注意,当您致电 为了完整性,值得注意的是,有一些低级别的黑客可以让你分配任何指针(不只是那些用 有关详细信息,请参阅conv2
时,即使您使用相同的mxArray
,也始终会创建新mxArray*
。< / p>
mxMalloc
和mxCalloc
创建的指针),但这些涉及猜测结构opaque类型mxArray
并做类似的事情:// effectively, mxSetPr(mxmat, Pr + n);
((mxArray_type_guess*)(mxmat))->data.number_array.pdata = (Pr + n);
mxSetPr
docs page。 mxArray
结构猜测可能已经过时了。据说您可以使用InplaceArray FEX submission确定正确的结构。