Matlab crashed when I run my mexFunction, anything wrong?

I wrote a mexFunction to execute the C code in Matlab. My C code takes in a single nested structure and output a single structure.
Anything wrong with my mexFunction?
/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
/* check proper input and output */
if( nrhs!= 1 )
{
mexPrintf( "There are [%d] inputs.\n", nrhs );
mexErrMsgIdAndTxt( "MATLAB:vdcmin_calc:invalidNumInputs",
"One input required." );
}
else if( nlhs > 1 )
{
mexPrintf( "There are [%d] outputs.\n", nlhs );
mexErrMsgIdAndTxt( "MATLAB:vdcmin_calc:maxlhs",
"Too many output arguments." );
}
else if( !mxIsStruct( prhs[0] ) )
{
mexErrMsgIdAndTxt( "MATLAB:vdcmin_calc:inputNotStruct",
"Input must be a structure." );
}
/* variable declarations here */
bus_CTCALC_SIM_INPUT *pInputBus;
bus_CTCALC_SIM_OUTPUT *pOutputBus;
mxArray *pInputTmp;
mxArray *pOutputTmp;
/* get a pointer to the input structure */
pInputTmp = mxGetPr( prhs[0] );
memcpy( pInputBus, pInputTmp, sizeof( bus_CTCALC_SIM_INPUT ) );
/* get a pointer to the output structure */
plhs[0] = mxCalloc( 1, sizeof( bus_CTCALC_SIM_OUTPUT ) );
pOutputBus = (bus_CTCALC_SIM_OUTPUT*) mxGetPr( plhs[0] );
/* code here */
vdcmin_calc( pInputBus, pOutputBus );
mxFree( plhs[0] );
//pOutputTmp = mxGetPr( plhs[0] );
//memcpy( pOutputTmp, pOutputBus, sizeof( bus_CTCALC_SIM_OUTPUT ) );
}

 采纳的回答

Several errors in the code that would result in a crash:
bus_CTCALC_SIM_INPUT *pInputBus;
:
/* get a pointer to the input structure */
pInputTmp = mxGetPr( prhs[0] );
memcpy( pInputBus, pInputTmp, sizeof( bus_CTCALC_SIM_INPUT ) );
In the above code, if prhs[0] is a struct then the data area of prhs[0] contains pointers to mxArrays (i.e., pointers to the field elements). So you copy the first mxArray pointer value to the memory behind the pInputBus pointer. But pInputBus is not initialized ... so it currently has a garbage value and you are writing to a random place in memory. This will certainly crash. It is unclear to me why you are even attempting to copy an mxArray pointer anyway. What are you really trying to do here?
/* get a pointer to the output structure */
plhs[0] = mxCalloc( 1, sizeof( bus_CTCALC_SIM_OUTPUT ) );
pOutputBus = (bus_CTCALC_SIM_OUTPUT*) mxGetPr( plhs[0] );
In the above code, plhs[0] should be a pointer to an mxArray. So it must be created with one of the mxCreateEtc functions (e.g., mxCreateDoubleMatrix). But you have instead assigned it some raw memory that is initialized to 0's. The subsequent mxGetPr(plhs[0]) passes a pointer to raw 0's memory to a routine that is expecting a pointer to a properly created mxArray. This will certainly crash. Even if you didn't do anything with plhs[0] in your mex routine, if this were passed back to the caller when the mex routine exited this would crash.
mxFree( plhs[0] );
Even if plhs[0] were created correctly, the above line of code would cause a crash. mxFree should only be used with memory created with mxMalloc, mxCalloc, or mxRealloc. To free the memory for an mxArray you must use mxDestroyArray. But even if you had used mxDestroyArray above (and plhs[0] were created properly), it would still crash because you would now be passing an invalid pointer back to the caller. As soon as MATLAB tried to use the pointer MATLAB would crash.
So ...
Almost nothing in your code is correct. Can you give a more detailed example of what the input is and what the desired output is? E.g., show us a specific structure that is input and then show us what the desired output would be.

9 个评论

Thanks James for your reply, I'm fairly new to mex files. I have existing C code that does a bounch of calculations and I want to bring it into Matlab so that I don't need to redo all the formulas in Matlab. The C code has a nested input structure and an output structure. In Matlab workspace, I created a data structure that mimics what we have in the C code and assign values to the structure in a Matlap script, after the input assignment I run the mex function to calculate the outputs. The roadblock that I have is how to pass the matlab structure into C code and read the outputs out into the workspace.
I assume the C struct definitions are in bus_CTCALC_SIM_INPUT and bus_CTCALC_SIM_OUTPUT. Can you show these definitions?
Sure.
typedef struct {
real32_T cycleTimeSec;
bus_CTCALC_tzINPUT inputBus;
bus_CTCALC_tzPARAMS parameterBus;
} bus_CTCALC_SIM_INPUT;
#endif
typedef struct {
bus_CTCALC_tzMEASUREMENT measurement;
} bus_CTCALC_tzINPUT;
#endif
typedef struct {
bus_tz_VAR v1;
bus_tz_VAR v2;
bus_tz_VAR i;
real32_T f;
real32_T v;
} bus_CTCALC_tzMEASUREMENT;
#endif
typedef struct {
real32_T dim1;
real32_T dim2;
} bus_tz_VAR
#endif
typedef struct {
real32_T param1;
real32_T param2;
real32_T param3;
real32_T param4;
real32_T param5;
real32_T param6;
real32_T param7;
real32_T param8;
} bus_CTCALC_tzPARAMS;
#endif
typedef struct {
bus_CTCALC_tzOUTPUT outputBus;
} bus_CTCALC_SIM_OUTPUT;
#endif
typedef struct {
real32_T output1;
real32_T output2;
real32_T output3;
} bus_CTCALC_tzOUTPUT;
#endif
So, even though these are nested structs at the C level, it looks like all of the actual data elements are real32_T (i.e., floats). Thus I would expect a good compiler to simply place them exactly next to each other in memory. So we could verify this by doing a sizeof( ) at the top level and see if everything adds up as expected. If this holds true, it would be simpler for you to rearrange all of the data as a single vector at the MATLAB level and then do a simple memcpy at the C level. Would you like me to write an example of this approach?
Update: Just checked with lcc compiler and it does indeed place all of the real32_T values next to each other in memory. E.g.,
mexPrintf("sizeof(bus_CTCALC_SIM_OUTPUT) = %d\n",sizeof(bus_CTCALC_SIM_OUTPUT));
mexPrintf("sizeof(bus_CTCALC_SIM_INPUT) = %d\n",sizeof(bus_CTCALC_SIM_INPUT));
produces:
sizeof(bus_CTCALC_SIM_OUTPUT) = 12
sizeof(bus_CTCALC_SIM_INPUT) = 68
So the suggested approach would work in this case.
I tried the following, but it doesn't work (Matlab doesn't crash, but can't get the input values in). I also printed out the size of pInputTmp , pInputBus and bus_CTCALC_SIM_INPUT. The results returns
8, 8 and 448.
bus_CTCALC_SIM_INPUT *pInputBus = (bus_CTCALC_SIM_INPUT*)mxCalloc( 1, sizeof( bus_CTCALC_SIM_INPUT ) );
const mxArray *pInputTmp;
pInputTmp = prhs[0];
if( sizeof( pInputTmp ) != sizeof( pInputBus ) )
{
mexErrMsgIdAndTxt( "MATLAB:vdcmin_calc:invalidNumInputs",
"Input strucure size wrong." );
}
else
{
memcpy( pInputBus, pInputTmp, sizeof( bus_CTCALC_SIM_INPUT ) );
}
sizeof( pInputTmp ) and sizeof( pInputBus ) are both always going to match because they are both defined as pointers, not as structs. I.e., their values will always be 4 or 8 regardless of what they point to. So this test is no doing what you expect. Compare it to my test above where I am calculating the size of the actual structs, not the size of pointers.
Also, you can't copy an mxArray directly into floating point memory like you are doing. It needs to be a data copy.
You are struggling with some concepts, so I will provide a simple example starting point. This example simply takes a 17-element single vector, copies the single values into a bus_CTCALC_SIM_INPUT struct, calls a function to do some calculations (here I simply copy some values) and produce an output struct, then copy the values from the output struct into a return mxArray variable.
/* Includes ----------------------------------------------------------- */
#include "mex.h"
#include <string.h> /* needed for memcpy */
/* typedef ------------------------------------------------------------ */
typedef struct {
real32_T output1;
real32_T output2;
real32_T output3;
} bus_CTCALC_tzOUTPUT;
typedef struct {
bus_CTCALC_tzOUTPUT outputBus;
} bus_CTCALC_SIM_OUTPUT;
typedef struct {
real32_T dim1;
real32_T dim2;
} bus_tz_VAR;
typedef struct {
bus_tz_VAR v1;
bus_tz_VAR v2;
bus_tz_VAR i;
real32_T f;
real32_T v;
} bus_CTCALC_tzMEASUREMENT;
typedef struct {
bus_CTCALC_tzMEASUREMENT measurement;
} bus_CTCALC_tzINPUT;
typedef struct {
real32_T param1;
real32_T param2;
real32_T param3;
real32_T param4;
real32_T param5;
real32_T param6;
real32_T param7;
real32_T param8;
} bus_CTCALC_tzPARAMS;
typedef struct {
real32_T cycleTimeSec;
bus_CTCALC_tzINPUT inputBus;
bus_CTCALC_tzPARAMS parameterBus;
} bus_CTCALC_SIM_INPUT;
/* Prototypes --------------------------------------------------------- */
void vdcmin_calc( bus_CTCALC_SIM_INPUT *, bus_CTCALC_SIM_OUTPUT *);
/* Gateway ------------------------------------------------------------ */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
bus_CTCALC_SIM_INPUT in;
bus_CTCALC_SIM_OUTPUT out;
if( nrhs != 1 || !mxIsSingle(prhs[0]) || mxGetNumberOfElements(prhs[0]) != 17 ) {
mexErrMsgTxt("Expected exactly one single input with 17 elements");
}
if( sizeof(bus_CTCALC_SIM_INPUT) != 17*4 ) {
mexErrMsgTxt("Unexpected size of internal struct bus_CTCALC_SIM_INPUT");
}
if( sizeof(bus_CTCALC_SIM_OUTPUT) != 3*4 ) {
mexErrMsgTxt("Unexpected size of internal struct bus_CTCALC_SIM_OUTPUT");
}
plhs[0] = mxCreateNumericMatrix( 1, 3, mxSINGLE_CLASS, mxREAL );
memcpy( &in, mxGetData(prhs[0]), 17*4 );
vdcmin_calc( &in, &out);
memcpy( mxGetData(plhs[0]), &out, 3*4 );
}
void vdcmin_calc( bus_CTCALC_SIM_INPUT *in, bus_CTCALC_SIM_OUTPUT *out)
{
out->outputBus.output1 = in->inputBus.measurement.v1.dim1;
out->outputBus.output2 = in->inputBus.measurement.v2.dim1;
out->outputBus.output3 = in->inputBus.measurement.i.dim1;
}
Note that if the calc function did not alter the input, I could have simply done this instead and avoided the memcpy altogether:
vdcmin_calc( mxGetData(prhs[0]), mxGetData(plhs[0]));
An example run:
>> x = single(rand(1,17))
x =
Columns 1 through 8
0.9157 0.7922 0.9595 0.6557 0.0357 0.8491 0.9340 0.6787
Columns 9 through 16
0.7577 0.7431 0.3922 0.6555 0.1712 0.7060 0.0318 0.2769
Column 17
0.0462
>> nested_struct2(x)
ans =
0.7922 0.6557 0.8491
Thanks James. Your answer above helped clarify several things. In your example, you passed in a vector. Can I pass in the whole structure? or mxArray only takes vector input.
If you pass in the whole structure, it will take a lot of code to manually copy the pieces to/from the mxArrays and the C structs. But it can be done. However, it would be much easier to take the pieces at the m-file level and form a single vector to pass in (and then use the code I show above). Similarly with the return values.
Thanks James. I have done 'a lot of code' to manually copy pieces yesterday. It ran successfully (got the correct result from the C code). I'll try the other way to see if everything works Ok.

请先登录,再进行评论。

更多回答(0 个)

类别

帮助中心File Exchange 中查找有关 Write C Functions Callable from MATLAB (MEX Files) 的更多信息

标签

Community Treasure Hunt

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

Start Hunting!

Translated by