Mixing M-Files and C or C++

Examples Overview

The examples in this section illustrate how to mix M-files and C or C++ source code files:

One way to create a standalone application is to code some of it as one or more function M-files and to code other parts directly in C or C++. To write a standalone application this way, you must know how to do the following:

For more information on MX Array, see Using MX Array.

Simple Example

This example involves mixing M-files and C code. Consider a simple application whose source code consists of mrank.m, mrankp.c, main_for_lib.c, and main_for_lib.h.

mrank.m

mrank.m contains a function that returns a vector of the ranks of the magic squares from 1 to n.

function r = mrank(n)
r = zeros(n,1);
for k = 1:n
   r(k) = rank(magic(k));
end

Copy mrank.m, printmatrix.m, mrankp.c, main_for_lib.c, and main_for_lib.h into your current directory.

Build Process

The steps needed to build this standalone application are:

  1. Compile the M-code.

  2. Generate the library wrapper file.

  3. Create the binary.

To perform these steps, enter the following on a single line:

mcc -W lib:libPkg -T link:exe mrank printmatrix mrankp.c 
main_for_lib.c

The following flow diagram shows the mixing of M-files and C-files that forms this sample standalone application. The top part of the diagram shows the mcc process and the lower part shows the mbuild process.

MATLAB Compiler generates the following C source code files:

This command invokes mbuild to compile the resulting MATLAB Compiler generated source files with the existing C source files (mrankp.c and main_for_lib.c) and link against the required libraries.

MATLAB Compiler provides two different versions of mrankp.c in the matlabroot/extern/examples/compiler directory:

mrankp.c

The code in mrankp.c calls mrank and outputs the values that mrank returns.

/*
 * MRANKP.C
 * "Posix" C main program
 * Calls mlfMrank, obtained by using MCC to compile mrank.m.
 *
 * $Revision: 1.1.4.45 $
 *
 */

#include <stdio.h>
#include <math.h>
#include "libPkg.h"

main( int argc, char **argv )
{
    mxArray *N;        /* Matrix containing n. */
    mxArray *R = NULL; /* Result matrix. */
    int      n;        /* Integer parameter from command line.*/

    /* Get any command line parameter. */
    if (argc >= 2) {
        n = atoi(argv[1]);
    } else {
        n = 12;
    }
    mclInitializeApplication(NULL,0);
    libPkgInitialize();/* Initialize library of M-Functions */
    
    /* Create a 1-by-1 matrix containing n. */
    N = mxCreateDoubleScalar(n);
    
    /* Call mlfMrank, the compiled version of mrank.m. */
    mlfMrank(1, &R, N);
    
    /* Print the results. */
    mlfPrintmatrix(R);
    
    /* Free the matrices allocated during this computation. */
    mxDestroyArray(N);
    mxDestroyArray(R);

    libPkgTerminate(); /* Terminate library of M-functions */
    mclTerminateApplication();
}

Explanation of mrankp.c

The heart of mrankp.c is a call to the mlfMrank function. Most of what comes before this call is code that creates an input argument to mlfMrank. Most of what comes after this call is code that displays the vector that mlfMrank returns. First, the code must initialize the MCR and the generated libPkg library.

mclInitializeApplication(NULL,0);
libPkgInitialize(); /* Initialize the library of M-Functions */

To understand how to call mlfMrank, examine its C function header, which is

void mlfMrank(int nargout, mxArray** r, mxArray* n);

According to the function header, mlfMrank expects one input parameter and returns one value. All input and output parameters are pointers to the mxArray data type. (See the External Interfaces documentation for details on the mxArray data type.)

To create and manipulate mxArray * variables in your C code, you can call the mx routines described in the External Interfaces documentation. For example, to create a 1-by-1 mxArray * variable named N with real data, mrankp calls mxCreateDoubleScalar.

N = mxCreateDoubleScalar(n);

mrankp can now call mlfMrank, passing the initialized N as the sole input argument.

R = mlfMrank(1,&R,N);

mlfMrank returns its output in a newly allocated mxArray * variable named R. The variable R is initialized to NULL. Output variables that have not been assigned to a valid mxArray should be set to NULL. The easiest way to display the contents of R is to call the mlfPrintmatrix function.

mlfPrintmatrix(R);

This function is defined in Printmatrix.m.

Finally, mrankp must free the heap memory allocated to hold matrices and call the termination functions.

mxDestroyArray(N);
mxDestroyArray(R);
libPkgTerminate();  /* Terminate the library of M-functions */
mclTerminateApplication();  /* Terminate the MCR */

Advanced C Example

This section provides an advanced example that illustrates how to write C code that calls a compiled M-file. Consider a standalone application whose source code consists of the files:

multarg.m specifies two input parameters and returns two output parameters.

function [a,b] = multarg(x,y)
a = (x + y) * pi;
b = svd(svd(a));

The code in multargp.c calls mlfMultarg and then displays the two values that mlfMultarg returns.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "libMultpkg.h"

/*
 * Function prototype; MATLAB Compiler creates mlfMultarg 
 * from multarg.m
 */

void PrintHandler( const char *text )
{
    printf(text);
}

int main( )   /* Programmer-written coded to call mlfMultarg */
{
#define ROWS  3 
#define COLS  3
    mclOutputHandlerFcn PrintHandler;
    mxArray *a = NULL, *b = NULL, *x, *y; 
    double  x_pr[ROWS * COLS] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    double  x_pi[ROWS * COLS] = {9, 2, 3, 4, 5, 6, 7, 8, 1}; 
    double  y_pr[ROWS * COLS] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    double  y_pi[ROWS * COLS] = {2, 9, 3, 4, 5, 6, 7, 1, 8}; 
    double *a_pr, *a_pi, value_of_scalar_b;

    /* Initialize with a print handler to tell mlfPrintMatrix
     * how to display its output.
     */
    mclInitializeApplication(NULL,0);
    libMultpkgInitializeWithHandlers(PrintHandler,PrintHandler);

    
    /* Create input matrix "x" */ 
    x = mxCreateDoubleMatrix(ROWS, COLS, mxCOMPLEX); 
    memcpy(mxGetPr(x), x_pr, ROWS * COLS * sizeof(double));
    memcpy(mxGetPi(x), x_pi, ROWS * COLS * sizeof(double));
    
    /* Create input matrix "y" */ 
    y = mxCreateDoubleMatrix(ROWS, COLS, mxCOMPLEX); 
    memcpy(mxGetPr(y), y_pr, ROWS * COLS * sizeof(double));
    memcpy(mxGetPi(y), y_pi, ROWS * COLS * sizeof(double));
    
    /* Call the mlfMultarg function. */
    mlfMultarg(2, &a, &b, x, y); 
    
    /* Display the entire contents of output matrix "a". */
    mlfPrintmatrix(a);
    
    /* Display the entire contents of output scalar "b" */
    mlfPrintmatrix(b);
    
    /* Deallocate temporary matrices. */
    mxDestroyArray(a);
    mxDestroyArray(b);
    libMultpkgTerminate();
    mclTerminateApplication();
    return(0);
}

You can build this program into a standalone application by entering this command on a single line:

mcc -W lib:libMultpkg -T link:exe multarg printmatrix
multargp.c main_for_lib.c

The program first displays the contents of a 3-by-3 matrix a, and then displays the contents of scalar b.

   6.2832 +34.5575i  25.1327 +25.1327i  43.9823 +43.9823i
  12.5664 +34.5575i  31.4159 +31.4159i  50.2655 +28.2743i
  18.8496 +18.8496i  37.6991 +37.6991i  56.5487 +28.2743i

  143.4164

Explanation of This C Code

Invoking MATLAB Compiler on multarg.m generates the C function prototype.

extern void mlfMultarg(int nargout, mxArray** a, mxArray** b, 
mxArray* x, mxArray* y);

This C function header shows two input arguments (mxArray* x and mxArray* y) and two output arguments (the return value and mxArray** b).

Use mxCreateDoubleMatrix to create the two input matrices (x and y). Both x and y contain real and imaginary components. The memcpy function initializes the components, for example:

x = mxCreateDoubleMatrix(,ROWS, COLS, mxCOMPLEX);
memcpy(mxGetPr(x), x_pr, ROWS * COLS * sizeof(double));
memcpy(mxGetPi(y), x_pi ROWS * COLS * sizeof(double));

The code in this example initializes variable x from two arrays (x_pr and x_pi) of predefined constants. A more realistic example would read the array values from a data file or a database.

After creating the input matrices, main calls mlfMultarg.

mlfMultarg(2, &a, &b, x, y); 

The mlfMultarg function returns matrices a and b. a has both real and imaginary components; b is a scalar having only a real component. The program uses mlfPrintmatrix to output the matrices, for example:

mlfPrintmatrix(a);
  


 © 1984-2008- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS