Using structures in MEX files

14 ビュー (過去 30 日間)
Jan Stolarek
Jan Stolarek 2011 年 12 月 24 日
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

採用された回答

James Tursa
James Tursa 2011 年 12 月 25 日
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 件のコメント
Jan
Jan 2011 年 12 月 25 日
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 2011 年 12 月 25 日
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.

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

Help Center および File ExchangeWrite 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