# 5.3 Introduction to cmex, Part I

Many people have requested a simple example on how to create a C MEX-file. In response to this request, the following C MEX-file, named mexample, is provided as an introduction to cmex programming. mexample is a commented program which describes how to use the following MEX-functions:

    mexErrMsgTxt
    mxCreateFull
    mxGetM
    mxGetN
    mxGetPr
    mxIsComplex
    mxIsSparse
    mxIsString

In MATLAB, mexample accepts two inputs and returns one output. The inputs are a 2x2 matrix denoted as MATRIX_IN and a 2x1 vector denoted as VECTOR_IN. The function calculates the determinant of MATRIX_IN, multiplies each element of VECTOR_IN by the determinant, and returns this as the output, denoted by VECTOR_OUT. All inputs and outputs to this function are assumed to be real (not complex).

------------------------------------------------------------

    /*      First, include some basic header files.  The header file "mex.h"
            is required for a MEX-file.  Add any other header files that
            your function may need here. */
    #include "mex.h"
    /*      A C MEX-file generally consists of two sections.  The first
            section is a function or set of functions which performs the
            actual mathematical calculation that the MEX-function is
            to carry out.  In this example, the function is called
            workFcn().  The second section is a gateway between MATLAB
            and the first section, and consists of a function called
            mexFunction.  The gateway is responsible for several tasks,
            including:
                      I)  error checking,
                     II)  allocating memory for return arguments,
                    III)  converting data from MATLAB into a format that the
                          workFcn function can use, and vice versa.
            The first function to be written in this example, then, is
            workFcn:
            Since C and MATLAB handle two-dimensional arrays differently, we
            will explicitly declare the dimension of the variable theMatrix.
            The variables, theVector and theResult, are both one-dimensional
            arrays, and therefore do not need such rigid typing.
            The #ifdef clause is intended so that both ANSI and non-ANSI
            compilers can compile this MEX-file. */
    #ifdef __STDC__
    void workFcn(
           double theMatrix[2][2],/* matrix with data from MATRIX_IN */
           double theVector[],    /* vector with data from VECTOR_IN */
           double theResult[]     /* vector with data for VECTOR_OUT */
            )
    #else
    void workFcn(theMatrix,theVector,theResult)
           double theMatrix[2][2];/* matrix with data from MATRIX_IN */
           double theVector[];    /* vector with data from VECTOR_IN */
           double theResult[];    /* vector with data for VECTOR_OUT */
    #endif                        /* __STDC__ */
    {
      double determinant;         /* determinant of theMatrix */
      determinant = theMatrix[0][0]*theMatrix[1][1]
                           -theMatrix[0][1]*theMatrix[1][0];

      theResult[0] = theVector[0]*determinant;
      theResult[1] = theVector[1]*determinant;
    }

    /*      Now, define the gateway function, i.e., mexFunction.  Below is
            the standard, predeclared header to mexFunction.  nlhs and
            nrhs are the number of left-hand and right-hand side arguments
            that mexample was called with from within MATLAB.  In this
            example, nlhs equals 1 and nrhs should equal 2.  If not, then
            the user has called mexample the wrong way and should be
            informed of this.  plhs and prhs are arrays which contain the
            pointers to the MATLAB matrices, which are stored in a C
            struct called a Matrix.  prhs is an array of length nrhs, and
            its pointers point to valid input data.  plhs is an array of
            length nlhs, and its pointers point to invalid data (i.e.,
            garbage).  It is the job of mexFunction to fill plhs with
            valid data.
            First, define the following values.  This makes it much easier
            to change the order of inputs to mexample, should we want to
            change the function later.  In addition, it makes the code
            easier to read. */
    #define MATRIX_IN prhs[0]
    #define VECTOR_IN prhs[1]
    #define VECTOR_OUT plhs[0]
    #ifdef __STDC__
    void mexFunction(
            int     nlhs,
            Matrix  *plhs[],
            int     nrhs,
            Matrix  *prhs[]
            )
    #else
    mexFunction(nlhs, plhs, nrhs, prhs)
    int nlhs, nrhs;
    Matrix *plhs[], *prhs[];
    #endif
    {
    double twoDarray[2][2];/* 2 dimensional C array to pass to workFcn() */
    int    row,col;        /* loop indices */
    int    m,n;            /* temporary matrix size holders */
    /*      Step 1: Error Checking
            Step 1a: is nlhs 1?  If not, generate an error message and exit
            mexample (mexErrMsgTxt does this for us!) */
      if (nlhs!=1)
        mexErrMsgTxt("mexample requires one output argument.");
    /*      Step 1b: is nrhs 2? */
      if (nrhs!=2)
        mexErrMsgTxt("mexample requires two input arguments, MATRIX_IN and
    \
    VECTOR_IN.");
    /*      Step 1c: Is MATRIX_IN a 2x2 numeric (nonstring), full (non-
            sparse), real (noncomplex) matrix? */
      if (mxGetM(MATRIX_IN)!=2 || mxGetN(MATRIX_IN)!=2 ||
          mxIsString(MATRIX_IN) || mxIsSparse(MATRIX_IN) ||
          mxIsComplex(MATRIX_IN))
          mexErrMsgTxt("First argument to mexample must be a 2x2, full, \
    numeric, real-valued matrix.");
    /*      Step 1d: Is VECTOR_IN a 2x1 or 1x2 numeric, full, real-valued
            vector? */
      m=mxGetM(VECTOR_IN);  /* Assigning result of mxGetM and mxGetN to
                               variables */
      n=mxGetN(VECTOR_IN);  /* with simpler names makes for easier code
                               reading.  */
      if (!((m==2 && n==1) || (m==1 && n==2)) ||
          mxIsString(VECTOR_IN) || mxIsSparse(VECTOR_IN)  ||
          mxIsComplex(VECTOR_IN))
          mexErrMsgTxt("Second argument to mexample must be 2 element, \
    full, numeric, real-valued vector.");
    /*      Step 2:  Allocate memory for return argument(s) */
      VECTOR_OUT = mxCreateFull(2, 1, REAL);  /* create a 2x1 full,
                                                 numeric, real-valued
                                                 matrix */
    /*      Step 3:  Convert MATRIX_IN to a 2x2 C array
            MATLAB stores a two-dimensional matrix in memory as a one-
            dimensional array.  If the matrix is size MxN, then the first M
            elements of the one-dimensional array correspond to the first
            column of the matrix, and the next M elements correspond to the
            second column, etc. The following loop converts from MATLAB
            format to C format: */
      for (col=0; col < mxGetN(MATRIX_IN); col++)
         for (row=0; row < mxGetM(MATRIX_IN); row++)
            twoDarray[row][col] =
            (mxGetPr(MATRIX_IN))[row+col*mxGetM(MATRIX_IN)];
    /*      mxGetPr returns a pointer to the real part of the matrix
            MATRIX_IN.  In the line above, it is treated as the one-
            dimensional array mentioned in the previous comment.  */
    /*      Step 4:  Call workFcn function */
      workFcn(twoDarray,mxGetPr(VECTOR_IN), mxGetPr(VECTOR_OUT));
    /*      workFcn will fill VECTOR_OUT with the return values for
            mexample, so the MEX-function is done!  To use it, compile it
            according to the instructions in the MATLAB External Interface
            Guide. Then, in MATLAB, type
            c=mexample([1 2; 3 4],[1 2])
            This will return the same as
            c=det([1 2; 3 4]) * [1 2]
    */
    }

(c) Copyright 1994 by The MathWorks, Inc.