In C code, you use structures (struct
) to store data in contiguous
locations in memory. You can organize data, such as signals and states, by using meaningful
names. Each structure acts as a namespace, so you can reuse a name to designate multiple data
items. Like arrays, with structures, you can write code that efficiently transfers and
operates on large amounts of data by using pointers.
By default, the code generator aggregates data into standard structures (see How Generated Code Stores Internal Signal, State, and Parameter Data). To control the characteristics of these structures or to override this default behavior by creating different structures, use the information in the table.
Goal | Technique |
---|---|
Control the characteristics of the standard data structures. For example, specify the names of the structure types, structure variables, and field names. | With Embedded Coder®, see Control Data Type Names in Generated Code. |
Control the placement of the structures in memory, for example, by inserting pragmas or other code decorations. | With Embedded Coder, see Control Data and Function Placement in Memory by Inserting Pragmas. |
Aggregate data into structures whose names and other basic characteristics you can control. As you add blocks and signals to the model, the resulting new data appears in these structures by default. | With Embedded Coder, apply a structured storage class to a category of data by using the Code Mapping Editor.
For more information about the Code Mapping Editor, see Configure Default C Code Generation for Categories of Data Elements and Functions. To create your own storage class, see Define Storage Classes, Memory Sections, and Function Templates for Software Architecture. |
Improve readability of the generated code by organizing individual data items into a custom structure whose characteristics you can finely control. | Create a
To create an array of structures, see Arrays of Structures. |
Exchange structured data between generated code and your external code, for example, when the external code already defines a custom structure type and a corresponding global variable. | Create a |
Reduce the number of arguments (formal parameters) for generated functions. |
|
Organize lookup table data into a structure. | Use Simulink.LookupTable and
Simulink.Breakpoint objects. See Simulink.LookupTable . |
Generate bit fields. | See Bitfields and Optimize Generated Code By Packing Boolean Data Into Bitfields. |
To create structures in the generated code, you can use these techniques:
Apply a structured storage class to categories of data by using the Code Mapping Editor. As you add blocks and signals to a model, new data elements acquire this storage class by default.
Apply a structured storage class, such as the built-in storage class
Struct
, directly to individual data items by using the Model Data
Editor.
Create custom nonvirtual buses and parameter structures.
To decide which techniques to use, use the information in the table.
Capability | Default Application of Structured Storage Class | Direct Application of Structured Storage Class | Nonvirtual Buses and Parameter Structures |
---|---|---|---|
Aggregate new data items into a structure by default | Yes | No | No |
Prevent elimination of the target data by optimizations (specify that the data appear in the generated code) | No | Yes | Only if you directly apply a storage class such as
ExportedGlobal to the bus or structure |
Aggregate data into a structure without changing the appearance of the block diagram | Yes | Yes | No |
Place signal, state, and parameter data in the same structure | No | Yes | No |
Include state data in a structure | Yes | Yes | No |
Organize structures into nested structures | No | No | Yes |
Organize structures into an array of structures | No | No | Yes |
Control name of structure type | Yes | Yes, but the type name derives from the variable name, which you specify | Yes |
Create a structure to reduce the number of arguments in a generated function | Yes, but you must create your own storage class by using an Embedded Coder Dictionary | No | Yes |
Requires Embedded Coder | Yes | Yes | No |
You can apply a default storage class to a category of model data. As you add blocks and
signals to the model, the associated data acquire the default storage class that you
specify. To aggregate new data into structures by default, you can apply structured storage
classes. You must use example storage classes ParamStruct
and
SignalStruct
created by the Quick Start tool or create your own storage
class by using an Embedded Coder Dictionary.
You cannot use default application to aggregate global data stores or global parameters (parameter objects that you store in the base workspace or a data dictionary).
To apply default storage classes, use the Code Mapping Editor. In a model window, in the Apps gallery, click Embedded Coder. Then, under Code Mappings > Data Defaults, apply storage classes by using the Storage Class column.
For more information about the Code Mapping Editor, see Configure Default C Code Generation for Categories of Data Elements and Functions. To create your own storage class by using an Embedded Coder Dictionary, see Create Code Definitions for Use in the Code Mappings Editor.
You can apply a structured storage class to individual data items. The direct application prevents code generation optimizations, such as Default parameter behavior and Signal storage reuse, from eliminating each data item from the generated code. The direct application also overrides the default storage classes that you specify with Code Mappings > Data Defaults.
To directly apply a storage class, use the Model Data Editor (on the
Modeling tab, click Model Data Editor). Set
Change view to Code
and apply the storage
class by using the Storage Class column.
For an example that shows how to use Struct
, see Configure Parameters for C Code Generation. For more information
about applying storage classes, see Organize Parameter Data into a Structure by Using Struct Storage Class.
To create a nonvirtual bus signal, use a Bus Creator block to
organize multiple signal lines into a single bus, or configure an
Inport block or Outport block as a nonvirtual bus. You
must create a Simulink.Bus
object that represents the structure type.
For an example, see Structures of Signals. For general information about nonvirtual buses, see Group Signal Lines into Virtual Buses.
To create a parameter structure, use MATLAB® commands or the Variable Editor to organize the values of multiple block
parameters into a MATLAB structure. Optionally, create a Simulink.Bus
object so
that you can control the name of the structure type and other characteristics such as
the data type and dimensions of each field. For an example, see Structures of Parameters. For general information about parameter
structures, see Organize Related Block Parameter Definitions in Structures.
Create a structure in the generated code. The structure stores parameter data.
C Construct
typedef struct { double G1; double G2; } myStructType; myStructType myStruct = { 2.0, -2.0 } ;
Procedure
1. Open the example model rtwdemo_paraminline
.
2. On the Modeling tab, click Model Data Editor. In the Model Data Editor, select the Parameters tab.
3. In the model, click the Gain block labeled G1
. In the Model Data Editor, use the Value column to set the value of the Gain parameter to myStruct.G1
.
4. Set the value of the Gain parameter in the G2
block to myStruct.G2
.
5. Next to myStruct.G2
, click the action button (with three vertical dots) and select Create.
6. In the Create New Data dialog box, set Value to Simulink.Parameter(struct)
and click Create. A Simulink.Parameter
object named myStruct
appears in the base workspace.
7. In the Simulink.Parameter property dialog box, next to the Value property, click the action button and select Open Variable Editor.
8. Right-click the white space under the Field column and select New. Name the new structure field G1
. Use the Value column to set the value of the field to 2
.
9. Add a field G2
whose value is -2
, and then close the Variable Editor.
10. In the Simulink.Parameter property dialog box, on the Code Generation tab, set Storage class to ExportedGlobal
. The structure myStruct
appears in the generated code as a global variable.
11. Generate code from the model.
Results
The generated header file rtwdemo_paraminline_types.h
defines a structure type that has a random name.
typedef struct { real_T G1; real_T G2; } struct_6h72eH5WFuEIyQr5YrdGuB;
The source file rtwdemo_paraminline.c
defines and initializes the structure variable myStruct
.
/* Exported block parameters */ struct_6h72eH5WFuEIyQr5YrdGuB myStruct = { 2.0, -2.0 } ; /* Variable: myStruct * Referenced by: * '<Root>/G1' * '<Root>/G2' */
Specify Name of Structure Type
1. Optionally, specify a name to use for the structure type definition (struct
). At the command prompt, use the function Simulink.Bus.createObject
to create a Simulink.Bus
object that represents the structure type.
2. The default name of the object is slBus1
. Change the name by copying the object into a new MATLAB variable.
3. In the Model Data Editor, click the Show/refresh additional information button.
4. In the data table, find the row that corresponds to myStruct
. Use the Data Type column to set the data type of myStruct
to Bus: myStructType
.
5. Generate code from the model.
The code generates the definition of the structure type myStructType
and uses this type to define the global variable myStruct
.
myStructType myStruct = { 2.0, -2.0 } ; /* Variable: myStruct
This example shows how to create a structure of signal data in the generated code.
C Construct
typedef struct { double signal1; double signal2; double signal3; } my_signals_type;
Procedure
To represent a structure type in a model, create a Simulink.Bus
object. Use the object as the data type of bus signals in your model.
1. Create the ex_signal_struct
model by using Gain blocks, a Bus Creator block, and a Unit Delay block. The Gain and Unit Delay blocks make the structure more identifiable in the generated code.
2. To configure the Bus Creator block to accept three inputs, in the block dialog box, set Number of inputs to 3
.
3. In the toolstrip, on the Modeling tab, under Design, click Bus Editor.
4. In the Bus Editor, click File > Add Bus to create a Simulink.Bus
object and name it my_signals_type
. Click File > Add/Insert BusElement to add three signal elements: signal1
, signal2
, and signal3
. For more information, see Create and Specify Simulink.Bus Objects.
5. Save the bus objects in your current folder as ex_signal_struct_data.mat
.
This bus object represents the structure type that you want the generated code to use.
6. In the Bus Creator block dialog box, set Output data type to Bus: my_signals_type
.
7. Select Output as nonvirtual bus. Click OK. A nonvirtual bus appears in the generated code as a structure.
8. Open the Simulink Coder app. In the C Code tab, select Code Interface > Individual Element Code Mappings.
9. Open the Signals/States tab. In the model, select the output signal of the Bus Creator block and click the Add selected signals to code mappings button in the Code Mappings editor.
11. For the added signal, set Storage Class to ExportedGlobal
.
12. In the Property Inspector, set the Code > Identifier property to sig_struct_var
. The output of the Bus Creator block appears in the generated code as a separate global structure variable named sig_struct_var
.
13. Generate code from the model.
Results
The generated header file ex_signal_struct_types.h
defines the structure type my_signals_type
.
typedef struct { real_T signal1; real_T signal2; real_T signal3; } my_signals_type;
The source file ex_signal_struct.c
allocates memory for the global variable sig_struct_var
, which represents the output of the Bus Creator block.
/* Exported block signals */ my_signals_type sig_struct_var; /* '<Root>/Bus Creator' */
In the same file, in the model step
function, the algorithm accesses sig_struct_var
and the fields of sig_struct_var
.
You can create nested structures of signal data in the generated code.
C Construct
typedef struct { double signal1; double signal2; double signal3; } B_struct_type; typedef struct { double signal1; double signal2; } C_struct_type; typedef struct { B_struct_type subStruct_B; C_struct_type subStruct_C; } A_struct_type;
Procedure
To represent a structure type in a model, create a Simulink.Bus
object. Use the object as the data type of bus signals in your model.
To nest a structure inside another structure, use a bus object as the data type of a signal element in another bus object.
1. Create the ex_signal_nested_struct
model with Gain blocks, Bus Creator blocks, and a Unit Delay block. The Gain and Unit Delay blocks make the structure more identifiable in the generated code.
2. To configure a Bus Creator block to accept three inputs, in the block dialog box, set Number of inputs to 3
.
3. In the toolstrip, on the Modeling tab, under Design, click Bus Editor.
In the Bus Editor, click File > Add Bus to create a Simulink.Bus
object and name it A_struct_type
. Click File > Add/Insert BusElement to add two signal elements: subStruct_B
and subStruct_C
. For more information, see Create and Specify Simulink.Bus Objects. This bus object represents the top-level structure type that you want the generated code to use.
4. Similarly, create Simulink.Bus
objects B_struct_type
(with three signal elements) and C_struct_type
(with two signal elements).
5. In A_struct_type
object, for the subStruct_B
element, set DataType to Bus: B_struct_type
and subStruct_C
to Bus: C_struct_type
.
Each signal element in A_struct_type
uses another bus object as a data type. Now, these elements represent substructures.
6. In the dialog box of the Bus Creator block that collects the three Gain signals, set Output data type to Bus: B_struct_type
. Click Apply.
7. Select Output as nonvirtual bus and click OK.
8. In the dialog box of the other subordinate Bus Creator block, set Output data type to Bus: C_struct_type
and select Output as nonvirtual bus. Click OK.
9. In the last Bus Creator block dialog box, set Output data type to Bus: A_struct_type
and select Output as nonvirtual bus. Click OK.
10. Open the Simulink Coder app. In the C Code tab, select Code Interface > Individual Element Code Mappings.
11. Open the Signals/States tab. In the model, select the output signal of the A_struct_type
Bus Creator block, which feeds the Unit Delay block. Click the Add selected signals to code mappings button in the Code Mappings editor.
12. For the added signal, set Storage Class to ExportedGlobal
.
13. In the Property Inspector, set the Code > Identifier property to sig_struct_var
. The output of the Bus Creator block appears in the generated code as a separate global structure variable named sig_struct_var
.
14. Generate code from the model.
Results
The generated header file ex_signal_nested_struct_types.h
defines the structure types. Each structure type corresponds to a Simulink.Bus
object.
typedef struct { real_T signal1; real_T signal2; real_T signal3; } B_struct_type; typedef struct { real_T signal1; real_T signal2; } C_struct_type; typedef struct { B_struct_type subStruct_B; C_struct_type subStruct_C; } A_struct_type;
The generated source file ex_signal_nested_struct.c
allocates memory for the global structure variable sig_struct_var
. By default, the name of the A_struct_type
Bus Creator block is Bus Creator2
.
/* Exported block signals */ A_struct_type sig_struct_var; /* '<Root>/Bus Creator2' */
In the same file, in the model step
function, the algorithm accesses sig_struct_var
and the fields of sig_struct_var
.
To work around some of the limitations of each technique, you can combine structured storage classes with nonvirtual buses and parameter structures. For example, you can:
Include a structure of signal data and a structure of parameter data in the same parent structure.
Nest structures while aggregating new data by default.
In the generated code, a flat parent structure, which corresponds to the structured storage class, contains substructures, which correspond to each bus and parameter structure. Choose one of these combined techniques:
Apply the structured storage class directly to each bus and parameter structure.
For example, set the storage class of two nonvirtual bus signals to
Struct
. Each bus appears in the generated code as a field
(substructure) of a single structure.
Leave the storage class of each bus and parameter structure at the default
setting, Auto
, or at Model
default
, which prevents code generation optimizations from eliminating
the bus or parameter structure. Then, configure default storage classes such that
signal data and parameter data use the structured storage class by default.
You can further package multiple consistent bus signals or parameter structures into an array. The array of buses or parameter structures appears in the generated code as an array of structures. To create arrays of buses, see Group Nonvirtual Buses in Arrays of Buses. To create arrays of parameter structures, see Group Multiple Parameter Structures into an Array.
By default, the code generator does not explicitly add padding fields to structure types.
Structure types can appear in the generated code through, for example, the standard data
structures (see Data Structures in the Generated Code), Simulink.Bus
objects, and
parameter structures that you use in a model.
However, when you use a code replacement library with Embedded Coder, you can specify data alignment (including structure padding) as part of the replacement library. For more information, see Provide Data Alignment Specifications for Compilers.
With built-in Simulink® Coder™ and Embedded Coder features, you cannot generate or use a custom structure that contains a field whose value is a pointer. You can do so manually by creating an advanced storage class and writing accompanying TLC code (see Finely Control Data Representation by Writing TLC Code for a Storage Class).
You cannot use the built-in storage class Struct
, or a
structured storage class that you create with the Custom Storage Class Designer (you
set the storage class property Type to
FlatStructure
), to set data defaults in the Code Mapping
Editor.