|
Here are some comments (Peter has already mentioned some of these
which I will repeat)
>1. The documentation in matlab is terrible on this. They
>either use a mxArray throughout the program or a scalar copy
>to pass in the data. Have they considered that a majority of
>users won't want to use mxArrays ? Its easier to port your
>function if you can copy stuff over to arrays.
Well, MATLAB stores data differently than C or C++, Fortran stores
data differently than C or C++, etc. etc. It should be expected that
any other language may store data differently than C or C++. It is not
fair to complain that you have to do something extra to get the data
from another language into yours. Since MATLAB has dynamic typing,
there is bound to be some overhead for their variables to take care of
this. Why should one be surprised at this? MATLAB has kindly provided
functions to extract the data into your C or C++ variables. Most of us
love MATLAB and are willing to live with this. As an analogy, how
would you get or manipulate data from a C++ class? Member functions,
right? What's the big deal about calling functions to get data from
the MATLAB mxArrays when this is what you do all the time for C++
classes to get at the data?
>2. A good way to dynamically allocate memory in c++ (I've
>forgotten how)
You might review "new". But as Peter mentioned, if you use mxMalloc
and mxCalloc you give the MATLAB memory manager a chance to clean up
all of your memory if something goes wrong.
>3. I can't copy data from *prhs to a double array (Vec in
>this case) in matlab. I can't even display the output, the
>code below when i call it from matlab has this output:
>
>test([1 3 5 4 5])
>F1 --- 0
>F1 --- 0
>F1 --- 0
>F1 --- 0
>F1 --- 0
>
>void mexFunction(int nlhs, mxArray *plhs[ ],int nrhs,
>xArray *prhs[ ]){
>int i,j,avg;
>mxArray *xData;
>double *xValues;
>int xrowLen, xcolLen;
>double temp;
>double Vec[];
>int ii,jj;
>
>xData = prhs[0];
>xValues = mxGetPr(xData);
>xrowLen = mxGetN(xData);
>xcolLen = mxGetM(xData);
>
>if(( xrowLen<1)|( xcolLen!=1)){
> mexErrMsgTxt("WARNING: ONLY PASS IN ROW VECTOR");
>}
>
>
>for(i=0;i<xrowLen;i++)
>{
> for(j=0;j<xcolLen;j++)
> {
> temp = xValues[i+j];
> printf("F1 --- %d \n",temp );
> Vec[i][j] = temp;
> }
>}
>}
Many specific comments about your code:
1) You are missing the #include "mex.h" line. You should include this
to make sure you get all the types defined, etc.
2) You misspelled mxArray as xArray in the argument list, and you did
not include the const attribute for prhs[].
3) This line is not the correct way to define an array:
>> double Vec[];
When you declare an array like this the compiler needs to know what
size it is, you can't leave the size blank. It appears that you would
like to declare Vec in such a way that you can later on use the
Vec[i][j] notation in your code for dereferencing a Vec element. You
can't do this in general. The compiler needs to know at compile time
exactly what type of pointer Vec is, meaning the compiler needs to
know the size and type of things that Vec points to at compile time.
You can't declare Vec at compile time to be an arbitrary sized array.
The most you can get away with is declaring a pointer to an array of a
fixed size and then allocate memory for it at run time, for instance:
double (*Vec)[5];
This declares Vec to be a pointer to an array of doubles of length 5
(but does not allocate any memory for such an array). Then later on in
your code you could allocate memory for Vec and use the Vec[i][j]
notation and it would work correctly. But this *only* works because
the compiler knows at compile time exactly what Vec points to. You
could not do this:
double (*Vec)[m];
where m was a variable defined at run time, because the size of things
that Vec points to is not known at compile time. So you are going to
have to live with doing the dereferencing arithmetic yourself as Peter
mentioned.
You could declare Vec as a simple pointer to double:
double *Vec;
and then use a macro to mimic the Vec[i][j] dereferencing (assuming
that the data was copied correctly into the memory that Vec points
to):
#define VEC(i,j) Vec[j+(i)*N]
But this is about as close as you will get to the actual Vec[i][j]
notation for a dynamically allocated size 2-dimensional matrix.
If Vec is pointing directly at a mxArray data location like this:
Vec = (double *) mxGetPr(prhs[0]);
Then you can simply reverse the indexing scheme of the macro to take
care of it in your C code (since MATLAB stores data column wise):
#define VEC(i,j) Vec[i+(j)*M]
3) You don't do any error checking of the inputs. The user might not
be giving this function what it expects, so the inputs should always
be checked. For example, your very first executable line xData =
prhs[0] will have a problem if the user calls the function with no
input arguments since prhs[0] will be invalid in this case.
4) The following lines are a bit confusing to me. Normally N is the
column and M is the row, but your are reversing that naming convention
with these lines. Not at all sure if this is intentional.
xrowLen = mxGetN(prhs[0]);
xcolLen = mxGetM(prhs[0]);
5) Why are you using the bit-wise or operator | in the following line?
It seems to clearly be a logical operation you are doing, not a
bit-wise operation. Admittedly you will wind up with the same logical
result in this particular case, but use of the | operator here instead
of || just doesn't look like good programming.
>> if(( xrowLen<1)|( xcolLen!=1)){
6) The dereferencing line temp = xValues[i+j], as Peter pointed out,
is not correct for an arbitrary size 2-dimensional dereferencing. It
only happens to work logically in your case because one of the
dimensions is 1 (which begs the question why is there a double loop
construct used here when one of them only loops on one value?).
7) You are using the incorrect format, %d, to print a double. You
should use %f. Also, use mexPrintf instead of printf.
>> printf("F1 --- %d \n",temp );
8) The use of more spacing would make your code much more readable.
I have included a working mex file below based on your example. I made
some assumptions about what you were actually after. Note that if you
comment out the following lines the mex function will work just fine
for any sized 2-dimensional array, not just row vectors.
// if( ( n < 1 ) || ( m != 1 ) ){
// mexErrMsgTxt("WARNING: ONLY PASS IN ROW VECTOR");
// }
James Tursa
#include "mex.h"
#define VEC(i,j) Vec[j+(i)*n]
#define XVALUES(i,j) xValues[i+(j)*m]
void mexFunction(int nlhs, mxArray *plhs[],int nrhs,
const mxArray *prhs[])
{
int i, j;
double *xValues;
int m, n;
double *Vec;
if (nrhs != 1)
mexErrMsgTxt("One input arguments required.");
if (nlhs > 0)
mexErrMsgTxt("Too many output arguments.");
if( !mxIsDouble(prhs[0]) )
mexErrMsgTxt("Argument need to be double.");
if( mxIsEmpty(prhs[0]) )
mexErrMsgTxt("Argument cannot be empty.");
xValues = mxGetPr(prhs[0]);
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
if( ( n < 1 ) || ( m != 1 ) ){
mexErrMsgTxt("WARNING: ONLY PASS IN ROW VECTOR");
}
Vec = (double *) mxCalloc(n*m, sizeof(double));
for( i=0; i<m; i++ )
{
for( j=0; j<n; j++ )
{
VEC(i,j) = XVALUES(i,j);
mexPrintf("VEC(%d,%d) = %f \n", i, j, VEC(i,j));
}
}
mxFree(Vec);
}
|