Generate Code for Variable-Size Arrays
MATLAB® represents scalars, vectors, and multidimensional matrices as arrays. A scalar is a 1-by-1 array, a vector is a 1-by-n or n-by-1 array, and a multidimensional matrix is an m-by-n-by-... array. During code generation, the code generator attempts to determine the size of each array dimension by following this process:
If the code generator cannot determine the size of an array dimension or if the size of the dimension changes, the code generator designates the dimension as variable size.
If a variable-size dimension has a fixed maximum size, the code generator designates the dimension as bounded variable-size.
If a variable-size dimension does not have a fixed maximum size, the code generator designates the dimension as unbounded.
If the code generator can determine that the size of an array dimension does not change, the code generator designates the dimension as fixed size.
Sometimes, the code generator incorrectly identifies a variable that changes size as fixed size. Under these circumstances, you can see a size-incompatibility error during code generation. For help diagnosing and resolving these errors, see Resolve Error: Arrays Have Incompatible Sizes.
You can learn whether the code generator has identified a variable-size dimension as fixed
size, bounded variable size, or unbounded by inspecting the code generation report. In the report, a colon (:
)
indicates that a dimension is variable size and a question mark (?
)
indicates that the size is unbounded. For example, a variable with a size of
1x:?
has a first dimension with a fixed size of 1 and a second
dimension that is variable size and unbounded. To
learn more about the code generation report, see Code Generation Reports.
Define Variable-Size Arrays
You can define variable-size arrays in the generated code by using one of these methods:
Create an array using a function such as
zeros
orones
with at least one nonconstant dimension.Assign multiple sizes to the same variable before using it.
Grow an array using
end+1
indexing.Explicitly declare a variable-size array by using
coder.varsize
.
For more information, see Define Variable-Size Data for Code Generation.
You can also specify variable-size input types by
using coder.Type
objects. You can create and edit
coder.Type
objects at the command line or by using the Coder Type
Editor. See Create and Edit Input Types by Using the Coder Type Editor.
For example, consider this function:
function out = demoVarsize(n) %#codegen x = ones(n,n); coder.varsize("y",[10,1],[true,false]) y = (1:n)'; z = 5; z(end+1) = 3; out = n; end
Generate code for this function, specifying
n
as a fixed-size scalar, and inspect the code generation report.
x
is size:?x:?
. Both dimensions are unbounded variable size.y
is size:10x1
. The first dimension is variable size with an upper bound of 10 and the second dimension has a fixed size of 1.z
is size1x:2
. The first dimension has a fixed size of 1 and the second dimension is variable size and has an upper bound of 2.n
is size1x1
. Both dimensions have a fixed size of 1.
If you generate code for this function and specify
n
as a variable-size scalar (:1x:1
), code
generation fails because the ones
function only accepts scalar
values.
Note
The code generator does not treat :1
as equivalent to 1. If
your function requires a scalar, you must pass a variable with a fixed size of
1x1
. If you pass a variable with a size of
:1x1
, 1x:1
, or
:1x:1
, code generation might fail or the generated code
might produce an error at run time. Similarly, if your function requires a
vector, one of the dimensions must have a fixed size of 1.
Differences in Variable-Size Array Implementation in C and C++ Code
The code generator implements dynamically allocated data in the generated code
differently depending on the target language. If you generate C, the code generator uses
a structure called an emxArray
. If you generate C++, the code
generator uses a class template called coder::array
. To learn how to use these data structures in the generated C or
C++ code, see Use Dynamically Allocated C Arrays in the Generated Function Interfaces or Use Dynamically Allocated C++ Arrays in Generated Function Interfaces,
respectively.
Memory Allocation for Variable-Size Arrays
By default, code generation support for variable-size arrays is enabled, and dynamic memory allocation is enabled for variable-size arrays whose size is greater than or equal to a configurable threshold. By default:
For fixed-size arrays, the code generator preallocates memory at code generation time.
For variable-size arrays with size less than the configured threshold, the code generator preallocates memory at code generation time.
For unbounded variable-size arrays, variable-size arrays whose size is determined at run time, and variable-size arrays with size greater than or equal to the configured threshold, the code generator allocates memory dynamically at run time.
Depending on the needs of your application, you can control variable-size support and memory allocation settings.
Disable Support for Variable-Size Arrays
If your application does not use variable-size data, disabling support for variable-size arrays can improve the performance of the generated code. To disable support for variable-size arrays, use one of these methods:
In a code configuration object, set the
EnableVariableSizing
parameter tofalse
.In the MATLAB Coder™ app, in the Memory settings, clear the Enable variable-sizing check box.
Control Dynamic Memory Allocation
Controlling dynamic memory allocation can help you to fine-tune the performance of the generated code. Dynamic memory allocation can reduce storage requirements on the stack. However, dynamically allocating memory at run time can reduce the speed of the generated code. To learn more about controlling dynamic memory allocation for variable-size arrays, see Control Memory Allocation for Variable-Size Arrays. To learn about controlling dynamic memory allocation for fixed-size arrays, see Control Dynamic Memory Allocation for Fixed-Size Arrays.
Generate Code for a MATLAB Function That Expands a Vector in a Loop
This example shows how to generate C and C++ code for a MATLAB® function that uses bounded and unbounded variable-size arrays.
Create MATLAB Function and Sample Data
Create a MATLAB function, myuniquetol
. This function identifies the elements of input vector A
that are unique with respect to the specified tolerance tol
. After sorting A
, the function iterates through the elements of A
. It adds element A(i)
to B
only if the absolute value of the difference between A(i)
and the element most recently added to B
is greater than tol
. The function then returns B
.
type myuniquetol.m
function B = myuniquetol(A,tol) A = sort(A); B = A(1); k = 1; for i = 2:length(A) if abs(A(k)-A(i)) > tol B = [B A(i)]; k = i; end end
Generate a 10-element vector of noisy values and use myuniquetol
to identify the unique elements of this vector given a tolerance of 0.05.
noisyData = 0.01*sin(1:10)+[1.01, 1.02, 1.03, 2.05, 2.10, 3.00, 3.01, 4.50, 5.00, 5.05]; cleanData = myuniquetol(noisyData,0.05)
cleanData = 1×5
1.0184 2.0424 2.9972 4.5099 5.0041
Prepare MATLAB Code for Code Generation
Rename the myuniquetol
function to myuniquetolCG
. Add the %#codegen
directive to myuniquetolCG
to prompt the MATLAB Code Analyzer to identify warnings and errors specific to code generation. Examine this function in the MATLAB Editor. The Code Analyzer detects that variable B
might change size in the for
-loop and issues a warning. Because vector B
expands in size when it adds values from vector A
, you can ignore this warning.
type myuniquetolCG.m
function B = myuniquetolCG(A,tol) %#codegen A = sort(A); B = A(1); k = 1; for i = 2:length(A) if abs(A(k)-A(i)) > tol B = [B A(i)]; k = i; end end
Generate and Test MEX Function
It is important to generate and test a MEX function before you generate C/C++ code. Running the MEX function in MATLAB before generating C/C++ code enables you to detect and fix run-time errors. In addition, you can use the MEX function to verify that your generated code functions similarly to your original MATLAB code.
Use the codegen
command to generate a MEX function from myuniquetolCG
. Use the -report
option to generate a report and use the -args
option to specify these input argument types:
Define the first input argument as a variable-length row vector with a maximum length of 100 by using
coder.typeof
.Define the second input argument as a fixed-size scalar by example.
codegen myuniquetolCG -args {coder.typeof(0,[1,100],[false,true]),0} -report
Code generation successful: View report
Open the report and examine the definitions in the Variables tab. B
is an unbounded row vector and A
is a variable-length vector with an upper bound length of 100.
Test the MEX function with the same input that you passed to the original MATLAB function and compare the results. The MEX function produces the same output.
cleanData_mex = myuniquetolCG_mex(noisyData,0.05)
cleanData_mex = 1×5
1.0184 2.0424 2.9972 4.5099 5.0041
Generate C Code
Generate a static C library for myuniquetolCG
and specify the same input arguments you used to generate the MEX function. By default, codegen
allocates memory statically for data whose size is less than the dynamic memory allocation threshold of 64 kilobytes. If the size of the array is greater than or equal to the threshold or if the array is unbounded, codegen
allocates memory dynamically on the heap.
codegen myuniquetolCG -config:lib -args {coder.typeof(0,[1,100],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because Embedded Coder is not installed, this might cause some Embedded Coder features to fail. Code generation successful (with warnings): View report
Examine the function declaration in the file myuniquetolCG.h
.
myfile = fullfile("codegen","lib","myuniquetolCG","myuniquetolCG.h"); coder.example.extractLines(myfile,"/* Function Declarations */",");",0,1)
extern void myuniquetolCG(const double A_data[], const int A_size[2], double tol, emxArray_real_T *B);
The code generator computes the size of A
and allocates this memory statically because the maximum size of A
is less than the default dynamic memory allocation threshold of 64 kilobytes. The generated function declaration contains:
double A_data[]
,which is the definition ofA
.const int A_size[2]
, which is the actual size of the input.double tol
, which is the definition oftol
.emxArray_real_T *B
, which is the definition ofB
.
The code generator determines that B
is variable size with unknown upper bounds, and represents B
as a variable-size array type known as an emxArray
. MATLAB Coder™ provides utility functions for creating and interacting with these types of arrays in the generated code. For more information, see Use Dynamically Allocated C Arrays in the Generated Function Interfaces.
Generate C++ Code
Generate a static C++ library for myuniquetolCG
, and specify the same input arguments you used to generate the MEX function. Use the -lang
option to specify C++ as the target language. To prevent the code generator overwriting the C code you generated previously, use the -d
option to specify a different output folder.
codegen myuniquetolCG -config:lib -lang:c++ -d myuniquetolCG_cpp -args {coder.typeof(0,[1,100],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because Embedded Coder is not installed, this might cause some Embedded Coder features to fail. Code generation successful (with warnings): View report
Examine the function declaration in the file myuniquetolCG.h
.
myfile = fullfile("myuniquetolCG_cpp","myuniquetolCG.h"); coder.example.extractLines(myfile,"// Function Declarations",");",0,1)
extern void myuniquetolCG(const double A_data[], const int A_size[2], double tol, coder::array<double, 2U> &B);
The generated C++ function declaration is similar to the C function declaration, except that the dynamically allocated array is a coder::array
class template instead of an emxArray
. To learn how to use the coder::array
class template in your custom C++ code, see Use Dynamically Allocated C++ Arrays in Generated Function Interfaces.
Generate C Code Using Dynamic Memory Allocation for Fixed-Size Input Array
Dynamic memory allocation can reduce the speed of the generated code. However, for larger arrays, dynamic memory allocation can reduce storage requirements. If you specify A
as a very large variable-size array, the code generator dynamically allocates memory for A
on the heap. For more information about controlling dynamic memory allocation for variable-size arrays, see Control Memory Allocation for Variable-Size Arrays.
codegen myuniquetolCG -config:lib -args {coder.typeof(0,[1,10000],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because Embedded Coder is not installed, this might cause some Embedded Coder features to fail. Code generation successful (with warnings): View report
myfile = fullfile("codegen","lib","myuniquetolCG","myuniquetolCG.h"); coder.example.extractLines(myfile,"/* Function Declarations */",");",0,1)
extern void myuniquetolCG(const emxArray_real_T *A, double tol, emxArray_real_T *B);
Generate C Code for Bounded Output Vector
Because input A
is variable size and has an upper bound of 100, the output vector B
contains at most 100 elements. Use coder.varsize
to set the upper-bound length of B
to 100 elements.
type myuniquetolCG_bounded.m
function B = myuniquetolCG_bounded(A,tol) %#codegen coder.varsize("B",[1,100],[false,true]); A = sort(A); B = A(1); k = 1; for i = 2:length(A) if abs(A(k)-A(i)) > tol B = [B A(i)]; k = i; end end
Generate code for this function, and specify the same input types you used to generate the MEX function. Examine the function declaration. The code generator statically allocates the memory for B
and stores the size of B
in int B_size[2]
.
codegen myuniquetolCG_bounded -config:lib -args {coder.typeof(0,[1,100],[false,true]),0} -report
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because Embedded Coder is not installed, this might cause some Embedded Coder features to fail. Code generation successful (with warnings): View report
myfile = fullfile("codegen","lib","myuniquetolCG_bounded","myuniquetolCG_bounded.h"); coder.example.extractLines(myfile,"/* Function Declarations */",");",0,1)
extern void myuniquetolCG_bounded(const double A_data[], const int A_size[2], double tol, double B_data[], int B_size[2]);