MEX调用后,MATLAB数组分配失败

时间:2016-12-16 16:42:08

标签: c++ matlab mex

我正在与MEX合作并获得奇怪的行为,我将其分离到以下非常简单的程序中:

#include "mex.h"
#include <stdio.h>

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  double *A;
  int i;

  if (    nrhs != 1
       || nlhs > 1
       || !mxIsDouble(prhs[0])
       || mxIsComplex(prhs[0])
       || mxGetM(prhs[0])!=1
    ) mexErrMsgTxt("internal error: dtimes2: input error");

  A = mxGetPr(prhs[0]);
  for (i=0; i<3; i++) A[i] *= 2;
  return; }

问题是这样的:在MATLAB会话中,

B=[3.2,5.6,9.4]; dtimes2(B); B

和MATLAB说:B = 6.4000 11.2000 18.8000

到目前为止一切顺利。但现在:

B=[3.2,5.6,9.4]

和MATLAB说:B = 6.4000 11.2000 18.8000

但是当我说

B=[-34.5,-57.6,-28.9]

然后MATLAB说:B = -34.5000 -57.6000 -28.9000

如果数字与以前相同,你会看到中间我无法重新分配B.所以,现实检查:

A=[1,2,3]; A=2*A; A=[1,2,3]

当然有效:MATLAB最后说A = [1,2,3]。

MEX警告我的编译器是&#39; 6.2.1-2&#39;但是支持的是#4.7; 4.7.x&#39;,但对于这个简单的程序,我几乎没有预料到会出现问题。这里出了什么问题?

2 个答案:

答案 0 :(得分:5)

您不应该修改进入MEX包装器的任何输入。这是未定义的行为,这就是您的MEX功能中发生的事情。 MEX建议您返回输出而不是改变输入。如果您真的希望改变输入或他所谓的就地编辑,您可以在Yair Altman的未记载的MATLAB博客中阅读更多相关信息。当你开始使用MEX时,我不鼓励这种行为。虽然有些情况值得,但除非你知道自己在做什么,否则请尽量避免:http://undocumentedmatlab.com/blog/matlab-mex-in-place-editing

至于不修改输入,这在mexFunction网关的功能声明中明确定义:

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
                                                      ^^^^^^^^^^^^^^^^^^^^^

const修饰符确保没有任何输入指针被更改,这很好......但这并不能阻止您实际修改指向内存的指针所指的内容或执行此操作<强>就地即可。一般而言,由于“惰性复制”行为,您为MATLAB工作空间中的任何MATLAB变量创建的内存可能与其他MATLAB变量共享。因此,您在矩阵,矢量或单个值中看到的值可能会链接到其他矩阵,向量或其他变量的单个值。当您就地更改内存时,您也会更改其他变量,这可能是您看到不一致行为的原因。

始终返回实际所需的输出而不是改变输入,因为您将保证获得正确的结果。我已修改下面的代码,以便输出新的矩阵而不是就地执行计算。

#include "mex.h"
#include <stdio.h>

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  double *A;
  double *B; // Change - For the output
  int i;

  if (    nrhs != 1
       || nlhs > 1
       || !mxIsDouble(prhs[0])
       || mxIsComplex(prhs[0])
       || mxGetM(prhs[0])!=1
    ) mexErrMsgTxt("internal error: dtimes2: input error");

  A = mxGetPr(prhs[0]);

  // Change - Create output memory
  mwSize rows = mxGetM(prhs[0]);
  mwSize cols = mxGetN(prhs[0]); 
  plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);

  // Change - get a pointer to the output memory
  B = mxGetPr(plhs[0]);

  for (i=0; i<3; i++) B[i] = 2*A[i]; // Change - Write to output memory
  return;
}

然后你会这样做:

B = dtimes2(B);

答案 1 :(得分:0)

我正在考虑发生了什么以及它是如何发生的,并且想要做一个注释来强调从MATLAB中更改不可变MATLAB对象的危险,以防有人帮助e 给定A = [1,2,3],MATLAB必须计算[1,2,3]的散列,比如“boo”,并将[1,2,3]存储在bin“boo”中。在MEX文件中,它愉快地放弃了指向[1,2,3]的指针,而强大的强C代码使该地址处的向量成为[2,4,6]。然后,在语句A = [1,2,3]上,MATLAB再次计算了哈希,它是相同的,即“boo”。由于会话很简单,因此该bin中只有一个对象。好吧,如果只有一个对象,它必须已经[1,2,3],那么为什么要重新写入内存呢?所以它没有。但记忆不是[1,2,3]它是[2,4,6],它本来就不应该在bin“boo”中。违规后,结果是以下对话:

ME:MATLAB,请设置A = [1,2,3]。

MATLAB:先生,是的,先生!做过某事! A = [2,4,6]!

我:不,真的,设置A = [1,2,3]。

MATLAB:先生,是的,先生! A = [2,4,6]!

我是的,好的。嗯,设A = [3,4,5]。

MATLAB:先生,是的,先生! A = [3,4,5]。

ME:所以,嗯,好的,现在设置A = [1,2,3]

MATLAB:先生,是的,先生! A = [2,4,6]!

每次执行错误的MEX文件时,生成的向量都在错误的哈希箱中。随机地,一些箱子只有一个错误的物体。这引起了极大的困惑。