Mexfunction variables error in structured variable array
I recently tried to write mexfunctions using structured variables. I watched the tutorial but got confused due to how variable values are passed. The following example ( mexfunction_using_ex_wrong.m & mexfunction_using_ex_wrong.cpp
) demonstrates how to retrieve the variables passed from matlab to mexfunction. However, in this case, the result is:
address i_c1=2067094464 i_c2=2067094464
i_c1=10 i_c2=10
address i_c1=1327990656 i_c2=2067100736
i_c1=2 i_c2=20
address i_c1=2067101056 i_c2=2067063424
i_c1=3 i_c2=30
As you can see, the first element of the array c1 and c2 of the structure variable coincides by chance.
But in another example ( mexfunction_using_ex_correct.m & mexfunction_using_ex_correct.cpp
) the elements of array 1 (b1) and array 2 (b2) of the structure variable are not related as I expect. Result:
address i_b1=1978456576 i_b2=1326968576
i_b1=1 i_b2=10
address i_b1=1978456584 i_b2=1326968584
i_b1=2 i_b2=20
address i_b1=1978456592 i_b2=1326968592
i_b1=3 i_b2=30
However, the first programming example is most often used. so can someone explain why in 1st example the addresses i_c1 and i_c2 are the same?
The following code: mexfunction_using_ex_wrong.m
clc
clear all
close all
mex mexfunction_using_ex_c_wrong.cpp;
a.b(1).c1=double(1);
a.b(2).c1=double(2);
a.b(3).c1=double(3);
a.b(1).c2=double(1);
a.b(2).c2=double(2);
a.b(3).c2=double(3);
mexfunction_using_ex_c_wrong(a);
The following code: mexfunction_using_ex_c_wrong.cpp
#include "mex.h"
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
int i, j, k;
double *i_c1;
double *i_c2;
// for struct variables(pointers) inside fcwcontext
mxArray *mx_b, *mx_c1, *mx_c2;
mx_b=mxGetField(prhs[0], 0, "b");
for(i = 0;i < 3;i=i+1)
{
mx_c1=mxGetField(mx_b, i, "c1");
mx_c2=mxGetField(mx_b, i, "c2");
i_c1=mxGetPr(mx_c1);
i_c2=mxGetPr(mx_c2);
*i_c2=(*i_c2)*10;
printf("address i_c1=%d i_c2=%d\n", i_c1, i_c2);
printf(" i_c1=%g i_c2=%g\n", *i_c1, *i_c2);
}
}
The following code: mexfunction_using_ex_c_correct.m
clc
clear all
close all
mex mexfunction_using_ex_correct.cpp;
a.b1(1)=double(1);
a.b1(2)=double(2);
a.b1(3)=double(3);
a.b2(1)=double(1);
a.b2(2)=double(2);
a.b2(3)=double(3);
mexfunction_using_ex_correct(a);
The following code: mexfunction_using_ex_c_correct.cpp
#include "mex.h"
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
int i, j, k;
double *i_b1;
double *i_b2;
mxArray *mx_b1, *mx_b2;
mx_b1=mxGetField(prhs[0], 0, "b1");
mx_b2=mxGetField(prhs[0], 0, "b2");
for(i = 0;i < 3;i=i+1)
{
i_b1=mxGetPr(mx_b1);
i_b2=mxGetPr(mx_b2);
i_b2[i]=i_b2[i]*10;
printf("address i_b1=%d i_b2=%d\n", &i_b1[i], &i_b2[i]);
printf(" i_b1=%g i_b2=%g\n", i_b1[i], i_b2[i]);
}
}
source to share
The addresses are not "accidentally the same" —they are intentionally the same, due to MATLAB's internal copy-for-write optimizations. If you look at the MEX documentation, you will see warnings scattered around ...
... in various forms ...
... trying to figure out that you absolutely shouldn't change whatever you get as input. By calling mxGetPr()
on the input data and writing back to that pointer, as you do with i_b2
and i_c2
, you get straight into this territory with "unpredictable results" - if you look at a.b(1).c1
in the MATLAB workspace after the call it will indeed be 10, even if you "only" changed c2
.
From MEX you are browsing the raw data store without any knowledge or internal access to MATLAB, so the only safe way to change anything is to use functions mxCreate*
or mxDuplicate*
to get your own safe arrays, you can do whatever you want and go to MATLAB via plhs
...
However, I would settle for abusing in-place modification to dramatically improve performance in a single instance, where I could ensure that my data was unique and not split, but this is unsupported at best and downright dangerous at worst.
source to share