Main Content

Call Custom C/C++ Code from the Generated Code

From within your MATLAB® code, you can directly call external C/C++ code, also called custom code or legacy code. To call C/C++ functions, use coder.ceval. The code generator integrates your C/C++ code into the C/C++ code generated from MATLAB. Integrate code when there are external libraries, optimized code, or object files developed in C/C++ that you want to use with your generated code. When the external code uses variable types that are not defined or recognized by MATLAB, use the coder.opaque function in conjunction with coder.ceval. To reserve certain identifier names for use in your custom C/C++ code that you want to integrate with the generated code, use the coder.reservedName function.

Following are some of the primary workflows for external code integration. For more examples, see the coder.ceval reference page.

Note

By using coder.ceval, you gain unrestricted access to external code. Misuse of these functions or errors in your code can destabilize MATLAB and cause it to stop working. To debug your code and analyze error messages from compilation, view the Build Logs tab in the code generation report.

Use coder.ceval only in MATLAB code intended for code generation. coder.ceval generates an error in uncompiled MATLAB code. To determine if a MATLAB function is executing in MATLAB, use coder.target. If the function is executing in MATLAB, call the MATLAB version of the C/C++ function.

Call C Code

This example shows how to integrate a simple C function with MATLAB® code by using coder.ceval. Consider the MATLAB function, mathOps:

function [added, multed] = mathOps(in1, in2)
added = in1+in2;
multed = in1*in2; 
end

For this example, suppose that you want to implement the addition operation by using external C code. Consider the C function, adder, implemented in the file adder.c:

#include <stdio.h>
#include <stdlib.h>
#include "adder.h"

double adder(double in1, double in2)
{
  return in1 + in2;
}

To integrate adder with your MATLAB code, you need a header file that contains the function prototype. See the file adder.h:

double adder(double in1, double in2);

Use the coder.ceval command to call the C function in mathOpsIntegrated.m. Include the header file by using coder.cinclude.

function [added, multed] = mathOpsIntegrated(in1, in2)
%#codegen
% for code generation, preinitialize the output variable
% data type, size, and complexity 
added = 0;
% generate an include in the C code
coder.cinclude('adder.h');
% evaluate the C function
added = coder.ceval('adder', in1, in2); 
multed = in1*in2; 
end

To generate code, use the codegen command. Specify the source file adder.c as an input. To test the C code, execute the MEX function and inspect the output results.

codegen mathOpsIntegrated -args {1, 2} adder.c

[test1, test2] = mathOpsIntegrated_mex(10, 20)
Code generation successful.


test1 =

    30


test2 =

   200

Return Multiple Values from a C Function

The C language restricts functions from returning multiple outputs. Instead, they return only a single, scalar value. The MATLAB functions coder.ref, coder.rref and coder.wref allow you to return multiple outputs from an external C/C++ function.

For example, suppose you write a MATLAB function foo that takes two inputs x and y and returns three outputs a, b, and c. In MATLAB, you call this function as follows:

[a,b,c] = foo(x,y)

If you rewrite foo as a C function, you cannot return three separate values a, b, and c through a return statement. Instead, create a C function with multiple pointer type arguments and pass the output parameters by reference. For example:

void foo(double x,double y,double *a,double *b,double *c)

Then you can call the C function from a MATLAB function by using the coder.ceval function.

coder.ceval('foo',x,y,coder.ref(a),coder.ref(b),coder.ref(c));

If your external C function only writes to or only reads from the memory that is passed by reference, you can use the coder.wref or coder.rref functions instead of coder.ref. Under certain circumstances, these functions can enable further optimization of the generated code. When you use coder.wref(arg) to pass arg by reference, your external C/C++ function must fully initialize the memory referenced by arg.

Pass Data by Reference

This example shows how to pass data by reference to and from an external C function.

Pass by reference is an important technique for C/C++ code integration. When you pass data by reference, the program does not need to copy data from one function to another. With pass by value, C code can return only a single scalar variable. With pass by reference, C code can return multiple variables, including arrays.

Consider the MATLAB function adderRef. This function uses external C code to add two arrays. The coder.rref and coder.wref commands instruct the code generator to pass pointers to the arrays, rather than copy them.

function out = adderRef(in1, in2)
%#codegen
out = zeros(size(in1)); 
% the input numel(in1) is converted to integer type 
% to match the cAdd function signature
coder.ceval('cAdd', coder.rref(in1), coder.rref(in2), coder.wref(out), int32(numel(in1)) );
end

The C code, cAdd.c, uses linear indexing to access the elements of the arrays:

#include <stdio.h>
#include <stdlib.h>
#include "cAdd.h"  

void cAdd(const double* in1, const double* in2, double* out, int numel)
{
    int i;
    for (i=0; i<numel; i++) {
        out[i] = in1[i] + in2[i];
    }
}

To build the C code you must provide a header file, cAdd.h, with the function signature:

void cAdd(const double* in1, const double* in2, double* out, int numel);

Test the C code by generating a MEX function and comparing its output with the output from the addition operation in MATLAB.

A = rand(2,2)+1;
B = rand(2,2)+10;

codegen adderRef -args {A, B} cAdd.c cAdd.h -report

if (adderRef_mex(A,B) - (A+B) == 0)
    fprintf(['\n' 'adderRef was successful.']);
end
Code generation successful: To view the report, open('codegen/mex/adderRef/html/report.mldatx')


adderRef was successful.

Integrate External Code that Uses Custom Data Types

This example shows how to call a C function that uses data types that are not natively defined within MATLAB®.

For example, if your C code performs file input or output on a C 'FILE *' type, there is no corresponding type within MATLAB. To interact with this data type in your MATLAB code, you must initialize it by using the function coder.opaque. In the case of structure types, you can use coder.cstructname.

For example, consider the MATLAB function addCTypes.m. This function uses coder.ceval with input types defined in external code. The function coder.opaque initializes the type in MATLAB.

function [out] = addCTypes(a,b)
%#codegen
% generate include statements for header files
coder.cinclude('MyStruct.h');
coder.cinclude('createStruct.h');
coder.cinclude('useStruct.h');
% initialize variables before use
in = coder.opaque('MyStruct');
out = 0;
% call C functions
in = coder.ceval('createStruct',a,b);
out = coder.ceval('useStruct',in); 
end


The createStruct function outputs a C structure type:

#include <stdio.h>
#include <stdlib.h>
#include "MyStruct.h"
#include "createStruct.h"

struct MyStruct createStruct(double a, double b) {
    struct MyStruct out;
    out.p1 = a;
    out.p2 = b;
    return out;
}

The useStruct function performs an operation on the C type:

#include "MyStruct.h"
#include "useStruct.h"

double useStruct(struct MyStruct in) {
    return in.p1 + in.p2;
}

To generate code, specify the source (.c) files as inputs:

codegen addCTypes -args {1,2} -report createStruct.c useStruct.c
Code generation successful: To view the report, open('codegen/mex/addCTypes/html/report.mldatx')

Integrate External Code that Uses Pointers, Structures, and Arrays

This example shows how to integrate external code that operates on a C style array with MATLAB® code. The external code computes a summation over array data. You can customize the code to change the input data or computation.

This example shows how to combine multiple different elements of external code integration functionality. For example, you:

  • Interface with an external structure type by using coder.cstructname

  • Interface with an external pointer type by using coder.opaque

  • Execute external code by using coder.ceval

  • Pass data by reference to external code by using coder.ref

Explore the Integrated Code

The extSum function uses external C code to compute a summation operation on an array of 32-bit integers. The array size is controlled by a user input.

function x = extSum(u)
%#codegen
% set bounds on input type to use static memory allocation
u = int32(u);
assert(0 < u && u < 101);
% initialize an array
temparray = int32(1):u;
% declare an external structure and use it
s = makeStruct(u);
x = callExtCode(s, temparray);


To simplify the generated code, you set bounds on the size of the array. The bounds prevents the use of dynamic memory allocation in the generated code.

The function makeStruct declares a MATLAB structure type and initializes one of the fields to a pointer type by using coder.opaque. The C structure corresponding to this definition is contained in a header file that you provide by using the HeaderFile parameter in the coder.cstructname function. The C structure type provides a simple representation for an array of integers.

function s = makeStruct(u)
% create structure type based on external header definition
s.numel = u;
s.vals = coder.opaque('int32_T *','NULL');
coder.cstructname(s,'myArrayType','extern','HeaderFile','arrayCode.h');

With the external structure type fully initialized, you pass it as an input to the external code in the callExtCode function. This function initializes the array, calls an operation on the array to return a single output, and then frees the initialized memory.

function x = callExtCode(s, temparray)
% declare output type
x = int32(0);
% declare external source file
coder.updateBuildInfo('addSourceFiles','arrayCode.c');
% call c code
coder.ceval('arrayInit',coder.ref(s),coder.ref(temparray));
x = coder.ceval('arraySum',coder.ref(s));
coder.ceval('arrayDest',coder.ref(s));

The function uses coder.updateBuildInfo to provide the .c file to the code generator.

Generate a MEX Function

To generate a MEX function that you can run and test in MATLAB, enter:

codegen extSum -args {10}
Code generation successful.

Test the MEX function. Enter:

extSum_mex(10)
ans =

  int32

   55

The external C code, contained in the files arrayCode.c and arrayCode.h, uses the custom type definition int32_T. The generated MEX code produces and uses this custom type definition. If you want to generate standalone (lib, dll, or exe) code that uses this custom data type, then you can modify the DataTypeReplacement property of your configuration object. See Mapping MATLAB Types to Types in Generated Code.

See Also

| | | | | | | |

Related Topics