Using structures in MEX files

20 views (last 30 days)
Jan Stolarek
Jan Stolarek on 24 Dec 2011
I'm learning how to use MEX files and I have a problem with using structures. I'm trying to convert to C a Matlab function that has a header like this:
writer = writeBit( writer, bit )
writer is a structure with four fields: buffer (1x1024 array interpreted as bytes), position (scalar), mask (scalar) and fileName (string).
I've created a mex file that looks like this:
#include <mex.h>
#include <string.h>
#include "writeBitC.h"
void mexFunction( int nlhs, mxArray *plhs[ ], int nrhs, const mxArray *prhs[ ] ) {
/*checking input & output params here*/
const char *fieldNames[] = {"buffer", "position", "mask", "fileName" };
mxArray* bufferArray = mxGetField( prhs[ 0 ],
0, fieldNames[ 0 ] );
mxArray* positionArray = mxGetField( prhs[ 0 ],
0, fieldNames[ 1 ] );
mxArray* maskArray = mxGetField( prhs[ 0 ],
0, fieldNames[ 2 ] );
mxArray* fileNameArray = mxGetField( prhs[ 0 ],
0, fieldNames[ 3 ] );
int bit = mxGetScalar( prhs[ 1 ] );
writer.position = ( (unsigned int) mxGetScalar(
positionArray ) ) - 1;
writer.mask = (char) mxGetScalar(
maskArray );
writer.fileName = (char*) mxGetChars( fileNameArray );
char* bufferDataPointer = (char*) mxGetChars(
bufferArray );
memcpy( writer.buffer, bufferDataPointer, BUFFER_SIZE );
writeBitC( bit );
memcpy( bufferDataPointer, writer.buffer, BUFFER_SIZE );
int dims[ 1 ] = { 1 };
plhs[ 0 ] = mxCreateStructArray( 1, dims, 4, fieldNames );
mxSetField( plhs[ 0 ], 0, fieldNames[ 0 ],
bufferArray );
mxSetField( plhs[ 0 ], 0, fieldNames[ 1 ],
mxCreateDoubleScalar( writer.position + 1 ) );
mxSetField( plhs[ 0 ], 0, fieldNames[ 2 ],
mxCreateDoubleScalar( writer.mask ) );
mxSetField( plhs[ 0 ], 0, fieldNames[ 3 ],
fileNameArray );
}
writeBitC is the function that performs all the operations on the structure. The writer structure is defined like this:
struct __writer {
char buffer[ BUFFER_SIZE ];
unsigned int position;
char mask;
char* fileName;
} writer;
writer is a global variable, so it's not passed to the writeBitC function as parameter. This code compiles but causes Matlab to freeze. I suspect that I did something wrong with the char arrays and memcpy function, but I can't track the bug :/ I would greatly appreciate some guidance.
Jan

Accepted Answer

James Tursa
James Tursa on 25 Dec 2011
I see the following issues:
1) You don't check your inputs before you use them. I would recommend putting in code to check that nrhs == 2, that prhs[0] is a structure, that prhs[0] has at least one element, that prhs[0] has the expected field names (i.e., that the results of your mxGetField calls are not NULL), that prhs[1] is a numeric scalar variable.
2) You use the result of a mxGetChars call, which returns type (mxChar * ), cast it to a (char * ) type, and then downstream attempt to use these pointers to access the data as char data. This will not work. The mxChar type is typcially a 2-byte per character type (MATLAB stores character data as 2-bytes each) whereas a char in C/C++ is 1-byte. You need to use mxArrayToString instead and convert the mxArray to a C-style character string, then use that for your downstream string processing in C, then use mxFree on that pointer to free the dynamically allocated C-style string you just created with mxArrayToString.
3) You cannot get a pointer from a field of an input mxArray (e.g., bufferArray) and simply attach it to a field of an output mxArray (i.e. plhs[0]) as you are doing. The MATLAB memory manager will likely get confused and crash later on since you have probably not told it everything it needs to know about how many copies of the data are around in memory. What you will probably need to do is either duplicate bufferArray with mxDuplicateArray and then attach that to the plhs[0] field, or use the undocumented function mxCreateSharedDataCopy to create a shared data copy of bufferArray and then attach that to the plhs[0] field.
4) You use BUFFER_SIZE for your copying, but you don't check to see that the inputs have at least that many characters to copy. Also, this won't copy a null character at the end since MATLAB strings do not terminate with null characters. Another reason to use the mxArrayToString function.
5) You are writing into bufferDataPointer, which is a data area of an input mxArray prhs[0]. This data memory can be shared at the MATLAB level with other variables, so changing it directly like you are doing has the potential unwanted side-effect of changing other MATLAB variables at the same time. This is generally not a good programming practice and can lead to strange downstream errors at the MATLAB level.
  3 Comments
Jan
Jan on 25 Dec 2011
plhs[0] is copied to the variable "ans", if it is not caught by the caller. Therefore it is a good idea to create it.
James Tursa
James Tursa on 25 Dec 2011
MATLAB always allocates plhs to hold 1 pointer in the event you don't call the function with any output arguments. As Jan Simon points out, this will become the ans variable at the MATLAB level in that case. If you check nlhs in the mex function you will see that it is 0, but it is *still* ok to put something in plhs[0] in this case since you are guaranteed that MATLAB has allocated enough array space for that first pointer element.

Sign in to comment.

More Answers (0)

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!