Matlab与C混合编程API之mxCreateStructMatrix
1 引言
在matlab中创建和操作结构体非常便捷,mathwork公司把这种便捷延伸到了桥梁函数中。matlab为桥梁函数定义了创建结构体的API: mxCreateStructMatrix
。
2 调用语法
mxCreateStructMatrix
的调用语法如下
#include "matrix.h" mxArray *mxCreateStructMatrix(mwSize m, mwSize n, int nfields, const char **fieldnames);
输入参数表如下:
参数名 | 描述 |
---|---|
m | 结构体矩阵的行数 |
n | 结构体矩阵的列数 |
nfields | 结构体矩阵中每个结构体域的个数 |
fieldnames | 结构体矩阵中每个结构体的域名 |
mxCreateStructMatrix
的返回值是一个指向 mxArray
的指针。我们还是通过一个例子来说明 mxCreateStructMatrix
的使用。
3 一个例子
这个例子实现了电话本功能,是目前为止用到的最复杂的例子。
1: #include "mex.h" 2: #include "string.h" 3: 4: #define MAXCHARS 80 /* max length of string contained in 5: each field */ 6: 7: /* the gateway routine. */ 8: void mexFunction( int nlhs, mxArray *plhs[], 9: int nrhs, const mxArray *prhs[] ) 10: { 11: /* pointers to field names */ 12: const char **fnames; 13: const mwSize *dims; 14: mxArray *tmp, *fout; 15: char *pdata=NULL; 16: int ifield, nfields; 17: mxClassID *classIDflags; 18: mwIndex jstruct; 19: mwSize NStructElems; 20: mwSize ndim; 21: 22: /* check proper input and output */ 23: if(nrhs!=1) 24: mexErrMsgIdAndTxt( 25: "MATLAB:phonebook:invalidNumInputs", 26: "One input required."); 27: else if(nlhs > 1) 28: mexErrMsgIdAndTxt( 29: "MATLAB:phonebook:maxlhs", 30: "Too many output arguments."); 31: else if(!mxIsStruct(prhs[0])) 32: mexErrMsgIdAndTxt( 33: "MATLAB:phonebook:inputNotStruct", 34: "Input must be a structure."); 35: /* get input arguments */ 36: nfields = mxGetNumberOfFields(prhs[0]); 37: NStructElems = mxGetNumberOfElements(prhs[0]); 38: /* allocate memory for storing classIDflags */ 39: classIDflags = mxCalloc(nfields, sizeof(mxClassID)); 40: 41: /* check empty field, proper data type, 42: * and data type consistency; 43: * and get classID for each field. */ 44: for(ifield=0; ifield<nfields; ifield++) { 45: for(jstruct = 0; jstruct < NStructElems; jstruct++) { 46: tmp = mxGetFieldByNumber(prhs[0], jstruct, ifield); 47: if(tmp == NULL) { 48: mexPrintf("%s%d\t%s%d\n", "FIELD: ", 49: ifield+1, "STRUCT INDEX :", jstruct+1); 50: mexErrMsgIdAndTxt( "MATLAB:phonebook:fieldEmpty", 51: "Above field is empty!"); 52: } 53: if(jstruct==0) { 54: if( (!mxIsChar(tmp) && !mxIsNumeric(tmp)) 55: || mxIsSparse(tmp)) { 56: mexPrintf("%s%d\t%s%d\n", "FIELD: ", ifield+1, 57: "STRUCT INDEX :", jstruct+1); 58: mexErrMsgIdAndTxt( "MATLAB:phonebook:invalidField", 59: "Above field must have either string or 60: numeric non-sparse data."); 61: } 62: classIDflags[ifield]=mxGetClassID(tmp); 63: } else { 64: if (mxGetClassID(tmp) != classIDflags[ifield]) { 65: mexPrintf("%s%d\t%s%d\n", "FIELD: ", ifield+1, 66: "STRUCT INDEX :", jstruct+1); 67: mexErrMsgIdAndTxt( "MATLAB:phonebook:invalidFieldType", 68: "Inconsistent data type in above field!"); 69: } else if(!mxIsChar(tmp) && 70: ((mxIsComplex(tmp) || mxGetNumberOfElements(tmp)!=1))){ 71: mexPrintf("%s%d\t%s%d\n", "FIELD: ", ifield+1, 72: "STRUCT INDEX :", jstruct+1); 73: mexErrMsgIdAndTxt( "MATLAB:phonebook:fieldNotRealScalar", 74: "Numeric data in above field must be scalar 75: and noncomplex!"); 76: } 77: } 78: } 79: } 80: 81: /* allocate memory for storing pointers */ 82: fnames = mxCalloc(nfields, sizeof(*fnames)); 83: /* get field name pointers */ 84: for (ifield=0; ifield< nfields; ifield++){ 85: fnames[ifield] = mxGetFieldNameByNumber(prhs[0],ifield); 86: } 87: /* create a 1x1 struct matrix for output */ 88: plhs[0] = mxCreateStructMatrix(1, 1, nfields, fnames); 89: mxFree((void *)fnames); 90: ndim = mxGetNumberOfDimensions(prhs[0]); 91: dims = mxGetDimensions(prhs[0]); 92: for(ifield=0; ifield<nfields; ifield++) { 93: /* create cell/numeric array */ 94: if(classIDflags[ifield] == mxCHAR_CLASS) { 95: fout = mxCreateCellArray(ndim, dims); 96: }else { 97: fout = mxCreateNumericArray(ndim, dims, 98: classIDflags[ifield], mxREAL); 99: pdata = mxGetData(fout); 100: } 101: /* copy data from input structure array */ 102: for (jstruct=0; jstruct<NStructElems; jstruct++) { 103: tmp = mxGetFieldByNumber(prhs[0],jstruct,ifield); 104: if( mxIsChar(tmp)) { 105: mxSetCell(fout, jstruct, mxDuplicateArray(tmp)); 106: }else { 107: mwSize sizebuf; 108: sizebuf = mxGetElementSize(tmp); 109: memcpy(pdata, mxGetData(tmp), sizebuf); 110: pdata += sizebuf; 111: } 112: } 113: /* set each field in output structure */ 114: mxSetFieldByNumber(plhs[0], 0, ifield, fout); 115: } 116: mxFree(classIDflags); 117: return; 118: }
代码中使用 mxGetNumOfFields
获得输入的结构体矩阵中每个结构体域的个数,使用 mxGetNumberOfElements
来获得输入结构体矩阵中结构体的个数。
plhs[0] = mxCreateStructMatrix(1, 1, nfields, fnames);
创建一个结构体保存输出。
mxSetFieldByNumber(plhs[0], 0, ifield, fout);
为输出结构体的每个域赋值。
假设我们的输入是
a.a =1; a.b =4; a.c = 'hello world'
调用 phonebook
n=phonebook(a);
则 n
的值为:
n.a =1; n.b =4; n.c ='hello world'
4 尾声
mxCreateStructMatrix
是matlab中创建结构体的API,方便matlab和C之间结构体类型数据的传递。