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);

输入参数表如下:

Table 1: mxCreateStructMatrix 输入参数对照表
参数名 描述
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之间结构体类型数据的传递。