Reputation: 717
I am confronting some pointer confusion:
I have some (Numerical Recipes) C-function fitexy(in, &out)
that I would like to compile as a .mex file to call it from matlab. However, I can not get the gateway routine to access the Pointer to out
so that it is passed to plhs[0]
, how do I do that?
The closest I get (in the sense of the least confusing error message) is this:
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]){
float *in;
float out;
in = (float *)mxGetData(prhs[0]);
plhs[0] = mxCreateNumericMatrix(1,1,mxSINGLE_CLASS,mxREAL);
out = (float *)mxGetData(plhs[0]);
fitexy(in, &out);
printf("out = %lf", &out); /*Prints the correct result to the screen*/
}
This results in an error message on compiling:
error: incompatible types when assigning to type ‘float’ from type ‘float *’
Which in not too surprising to me, but not very helpful either. I tried to cast / dereference the output of mxGetData(plhs[0])
,
out = (float &)mxGetData(plhs[0]);
which seems to be kind of nonsense,
out = (float)mxGetData(plhs[0]);
which conflicts with out
being a variable and mxGetData(plhs[0])
a pointer.
I already found Save a variable (float *) to plhs and How to return a float value from a mex function, and how to retrieve it from m-file?, but they both deal with casting rather than dereferencing .
I understand cannot convert parameter 2 from 'mxArray **' to 'mwArray &', but it does not help me, because I can not (i.e. would prefer not to) change the call to my C-routine.
Any help is warmly appreciated, thank a lot!
Upvotes: 2
Views: 657
Reputation: 124563
Suppose you have a C function fit_line
with the following signature:
void fit_line(float x[], float y[], int n, float *a, float *b);
It takes two input data arrays x
and y
of length n
, and fits a straight line y = a*x + b
in the least-squares sense by computing the quatities a
and b
.
Here is how I would write the MEX function:
#include "mex.h"
EXTERN_C void fit_line(float x[], float y[], int n, float *a, float *b);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
/* validate inputs */
if (nrhs!=2 || nlhs>2)
mexErrMsgIdAndTxt("mex:err", "wrong num args");
if (!mxIsSingle(prhs[0]) || mxIsComplex(prhs[0]) || mxIsSparse(prhs[0]) ||
!mxIsSingle(prhs[1]) || mxIsComplex(prhs[1]) || mxIsSparse(prhs[1]))
mexErrMsgIdAndTxt("mex:err", "expecting dense real single arrays");
if (mxGetNumberOfElements(prhs[0]) != mxGetNumberOfElements(prhs[1]))
mexErrMsgIdAndTxt("mex:err", "length dont match");
/* get data arrays */
mwSize len = mxGetNumberOfElements(prhs[0]);
float *x = (float*) mxGetData(prhs[0]);
float *y = (float*) mxGetData(prhs[1]);
if (x==NULL || y==NULL) mexErrMsgIdAndTxt("mex:err", "null ptr");
/* call external function */
float a, b;
fit_line(x, y, len, &a, &b);
/* assign output */
plhs[0] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
*((float*) mxGetData(plhs[0])) = a;
if (nlhs>1) {
plhs[1] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
*((float*) mxGetData(plhs[1])) = b;
}
}
After we compile it, we can call the MEX function from MATLAB as:
% some random data
x = randn(100,1,'single');
y = -1.5*x + 1 + randn(size(x),class(x))*0.9;
% fit least-square line
[a,b] = mex_fit_line(x,y);
% plot data and fitted line
xx = linspace(min(x), max(x), 50);
yy = a*xx + b;
plot(x, y, 'b.')
line(xx,yy, 'Color','r')
axis equal, legend({'data', 'LS line'})
title(sprintf('y = %.2f*x + %.2f', a, b)), xlabel('X'), ylabel('Y')
Upvotes: 2
Reputation: 91017
Why don't you just define out
to be a pointer?
float * out;
This way you can easily do
out = (float *)mxGetData(plhs[0]);
and you can use the out
for writing a result value. If I am not mistaken about the fitexy()
function, you can call it with
fitexy(in, out);
.
Upvotes: 3