Simple mex function help

 Accepted Answer

James Tursa
James Tursa on 15 Jul 2014
Edited: James Tursa on 15 Jul 2014
You have defined x and y in mexFunction to be pointers to double, not double. But your xtimes10 routine is expecting double, not pointer to double. Hence the error. Also, unrelated, you create plhs[0] twice which is unnecessary. One way to fix things is to have the xtimes10 routine work with pointers, and dereference them inside the routine. E.g.,
#include "mex.h" // Matlab mex header file
// C function multiply arrays x and y (of size) to give z
void xtimes10(double *x, double *y)
{
*y = *x * 10;
}
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *x,*y;
x = mxGetPr(prhs[0]);
plhs[0] = mxCreateDoubleMatrix( 1 , 1, mxREAL);
y = mxGetPr(plhs[0]);
xtimes10(x,y);
mexPrintf("result y= %g\n", y);
}
Also you will notice that I fixed your mexPrintf call. It was named incorrectly, and you were using the wrong format for a double (%d is for integer types), and you did not have a newline.

8 Comments

would this work as well? The matlab code that is called in is below. I tried this and got "Undefined function 'xtimes10' for input arguments of type 'double'." returned from running the matlab program.
#include "mex.h" // Matlab mex header file
// C function multiply arrays x and y (of size) to give z
void xtimes10(double x, double y)
{
y=x*10;
}
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double x,y;
prhs[0] = mxCreateDoubleMatrix(1,1, mxREAL);
x = *mxGetPr(prhs[0]);
plhs[0] = mxCreateDoubleMatrix( 1 , 1, mxREAL);
y = *mxGetPr(plhs[0]);
xtimes10(x,y);
printf("result y= %d", y);
}
Matlab:
x=5.567
y=xtimes10(x)
1) You probably forgot to mex the function, so MATLAB can't find any function named xtimes10.
2) No, what you have will not work because, among other things (more on that later), there is no connection between the y in mexFunction and the return mxArray plhs[0]. Here is a blow by blow of what is wrong:
prhs[0] = mxCreateDoubleMatrix(1,1, mxREAL);
The above line violates the const attribute of prhs[0] in the argument list. You, the programmer, DO NOT create prhs[0]. Rather, prhs[0] is the input that is handed to you by the calling routine. In your case, prhs[0] will be the address of the x variable from the MATLAB command line. It was already created at the MATLAB level. You are not supposed to change ANY of the prhs[...] values.
x = *mxGetPr(prhs[0]);
Assume for the moment that you did NOT do the prhs[0] = etc line above. Then what the above line would do would get the address of the first double element of the input variable (the x from the MATLAB command line), then dereference it to get the value 5.567, then store that value in the mexFunction x variable.
plhs[0] = mxCreateDoubleMatrix( 1 , 1, mxREAL);
The above line creates a 1x1 double mxArray and initializes the one double element as 0.0. The address of this mxArray is stored in plhs[0].
y = *mxGetPr(plhs[0]);
The above line gets the address of the first double element of the mxArray plhs[0], then dereferences that address (to get the value 0.0), and then stores that 0.0 value in y.
xtimes10(x,y);
The above line makes COPIES of x and y and passes them into the xtimes10 routine. (i.e., places copies of x and y values on the stack for xtimes10 to use). So the values 5.567 and 0.0 are passed into xtimes10.
void xtimes10(double x, double y){
y=x*10;
Inside the xtimes10 routine, the x variable (copy of 5.567, residing on the stack) is multiplied by 10, resulting in 55.67. This value is then stored in y (which came in with a copy of the value 0.0), which also resides on the stack.
printf("result y= %d", y);
When the xtimes10 function returns, all of the variable copies that were placed on the stack are thrown away. In particular, the new value for y, 55.67, is thrown away. So the above line simply prints the original value that was in place before the call, 0.0. Or at least attempts to ... in this case you are using an incorrect format of %d which will not work for double variables. You need to use something like %g or %f to print out floating point variables.
BOTTOM LINE: In C, to change a value with a function call, you either need to pass in pointers and work with pointers in the routine, OR you need to pass the resulting value back out as a result of the function (not through a value of a stack variable).
Thank's a TON! I was having a really hard time with this mex function stuff... Any chance you could give me some pointers (pun intended) with converting matlab structs to c and then to mex?
It's this struct:
function [local] = LocalInfo(Euler, k, q, qh, forcing)
% Extract local info for element k
% local struct
local = [];
local.force = feval(forcing, Euler, Euler.x(:,k));
local.q = squeeze(q(:,k,:));
local.q0 = squeeze(Euler.q0(:,k,:));
local.nx = Euler.nx(:,k);% normal vector
local.J = Euler.J(1,k);
local.rx = Euler.rx(1,k);
local.qh = reshape(qh(k:k+1,:),[],1);
local.k = k;
This is what I have so far in .c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mex.h>
/* Extract local info for element k */
/* local struct */
typedef struct
{
double force;
double q;
double q0;
double nx;
double J;
double rx;
double qh;
double k;
} LocalInfo;
int main()
{
LocalInfo Local;
Local.force = forcing(Euler, Euler.x(:,k));
Local.q = squeeze(q(:,k,:));
Local.q0 = squeeze(Euler.q0(:,k,:));
Local.nx = Euler.nx(:,k); // normal vector
Local.J = Euler.J(1,k);
Local.rx = Euler.rx(1,k);
Local.qh = reshape(qh(k:k+1,:),[],1);
Local.k = k;
return 0;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
}
Bare bones with NO argument checking (i.e., will crash MATLAB if anything is not exactly as expected), assuming the first input to the mex routine is the struct you show above, and all of the fields are in fact scalars:
#include "mex.h"
/* Extract local info for element k */
/* local struct */
typedef struct
{
double force;
double q;
double q0;
double nx;
double J;
double rx;
double qh;
double k;
} LocalInfo;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mxArray *field;
LocalInfo Local;
field = mxGetField(prhs[0],0,"force");
Local.force = mxGetScalar(field);
field = mxGetField(prhs[0],0,"q");
Local.q = mxGetScalar(field);
field = mxGetField(prhs[0],0,"q0");
Local.q0 = mxGetScalar(field);
field = mxGetField(prhs[0],0,"nx");
Local.nx = mxGetScalar(field);
field = mxGetField(prhs[0],0,"J");
Local.J = mxGetScalar(field);
field = mxGetField(prhs[0],0,"rx");
Local.rx = mxGetScalar(field);
field = mxGetField(prhs[0],0,"qh");
Local.qh = mxGetScalar(field);
field = mxGetField(prhs[0],0,"k");
Local.k = mxGetScalar(field);
}
Well... it compiled as a mex. Can you explain this to me? I'm sorry I am so incompetent with this. I get the typedef struct part, but the mexfunction part I don't understand what is going on... Thanks again for your help.
LocalInfo Local;
Creates a local C struct variable Local with the fields based on your typedef.
field = mxGetField(prhs[0],0,"force");
Gets the address of the "force" field (no pun intended) from the 1st element of the prhs[0] MATLAB struct. (The 0 index being the 1st element). This will itself be an mxArray* value, which is stored in the local variable "field".
Local.force = mxGetScalar(field);
Gets the first data value from the mxArray pointed to by field, converts it to double if necessary, and then copies that value into Local.force.
Other line pairs are similar.
Thanks for that clarification. On another note... I typed LocalInfo in the command window and got a MATLAB System Error notification... Am I just not supposed to be able to call LocalInfo from the command window or is there a problem with the mex?
If you type LocalInfo with no input, then yes you will get a crash because prhs[0] is not defined but LocalInfo tries to access it. That is why I made the point of "bare bones". To be production quality code (i.e., not crash MATLAB), you would need to put in checks for this, which can take up a lot of code but is necessary to be robust. E.g.,
if( nrhs != 1 ) {
mexErrMsgTxt("Expecting exactly one input");
}
if( !mxIsStruct(prhs[0]) ) {
mexErrMsgTxt("Input must be a struct");
}
etc etc
Basically, you need to check that the number of inputs is as expected, that the class of the inputs is as expected, that the sizes are as expected, that the fields you expect to be there are actually there, that the fields are not empty, etc. etc. I.e., you need to check everything before you use it. I leave that up to you.

Sign in to comment.

More Answers (0)

Categories

Asked:

on 15 Jul 2014

Edited:

on 16 Jul 2014

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!