MATLAB在mex文件中到达mxSetPr时崩溃

时间:2014-11-21 07:07:41

标签: matlab mex

我正在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] );

}

1 个答案:

答案 0 :(得分:2)

传递给mxSetPr的内存必须分配mxMallocmxCalloc,而不是mallocnew等。来自{{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使用mxMallocmxCalloc

mxSetPr与创建mxArray*的函数不同的另一个有趣的惊喜是当myconv2存在时,MATLAB也会尝试销毁每个mxArrayrhs[]中。假设您希望调用者对这些数组负责,然后在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>


为了完整性,值得注意的是,有一些低级别的黑客可以让你分配任何指针(不只是那些用mxMallocmxCalloc创建的指针),但这些涉及猜测结构opaque类型mxArray并做类似的事情:

// effectively, mxSetPr(mxmat, Pr + n); 
((mxArray_type_guess*)(mxmat))->data.number_array.pdata = (Pr + n);

有关详细信息,请参阅mxSetPr docs pagemxArray结构猜测可能已经过时了。据说您可以使用InplaceArray FEX submission确定正确的结构。