Main Content

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 or ones 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 size 1x: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 size 1x1. 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 to false.

  • 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 of A.

  • const int A_size[2], which is the actual size of the input.

  • double tol, which is the definition of tol.

  • emxArray_real_T *B, which is the definition of B.

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]);

See Also

Topics