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
codegen
| coder.wref
| coder.ceval
| coder.rref
| coder.ref
| coder.cinclude
| coder.cstructname
| coder.opaque
| coder.reservedName