Organize Data into Structures in Generated Code
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 Manage Replacement of Simulink Data Types in Generated Code (Embedded Coder). |
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 (Embedded Coder). |
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 (Embedded Coder). To create your own storage class, see Define Service Interfaces, Storage Classes, Memory Sections, and Function Templates for Software Architecture (Embedded Coder). |
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 (Embedded Coder) and Optimize Generated Code by Packing Boolean Data into Bitfields (Embedded Coder). |
Techniques to Create Structures
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 |
Default Application of Structured Storage Class
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 (Embedded Coder). To create your own storage class by using an Embedded Coder Dictionary, see Create Code Definitions for Use in the Code Mappings Editor (Embedded Coder).
Direct Application of Structured Storage Class
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 (Embedded Coder). For more information
about applying storage classes, see Organize Parameter Data into a Structure by Using Struct Storage Class (Embedded Coder).
Nonvirtual Buses and Parameter Structures
To create a nonvirtual bus, 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 information about nonvirtual buses, see Create Nonvirtual 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.
Structures of Parameters
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 InlineBlockParameters
.
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, in the Value box, type Simulink.Parameter(struct)
. From the Location list, select Base Workspace
. 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 InlineBlockParameters_types.h
defines a structure type that has a random name.
typedef struct { real_T G1; real_T G2; } struct_6h72eH5WFuEIyQr5YrdGuB;
The source file InlineBlockParameters.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
Structures of Signals
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 buses 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, in the Design gallery, click Type Editor.
4. In the Type Editor, create a Simulink.Bus
object named my_signals_type
that contains elements named signal1
, signal2
, and signal3
. For more information, see Type Editor.
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
.Select Output as nonvirtual bus. A nonvirtual bus appears in the generated code as a structure.
Click OK.
7. Open the Simulink Coder app. In the C Code tab, select Code Interface > Individual Element Code Mappings.
8. 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.
9. For the added signal, set Storage Class to ExportedGlobal
.
10. 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
.
11. 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
.
Nested Structures of Signals
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 buses in your model.
To nest a structure inside another structure, use a bus object as the data type of an 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.
To configure a Bus Creator block to accept three inputs, in the block dialog box, set Number of inputs to 3
.
2. In the toolstrip, on the Modeling tab, in the Design gallery, click Type Editor.
3. In the Type Editor, create three Simulink.Bus
objects:
A bus object named
A_struct_type
with two elements namedsubStruct_B
andsubStruct_C
A bus object named
B_struct_type
with three elements namedsignal1
,signal2
, andsignal3
A bus object named
C_struct_type
with two elements namedsignal1
andsignal2
The bus object named A_struct_type
represents the top-level structure type that you want the generated code to use.
For information on how to create bus objects and their elements, see Type Editor.
4. In the A_struct_type
object, use the other bus objects as data types.
For the
subStruct_B
element, set DataType toBus: B_struct_type
.For the
subStruct_C
element, set DataType toBus: C_struct_type
.
Each element in A_struct_type
uses another bus object as a data type. These elements represent substructures.
5. In the dialog box of the Bus Creator block that receives signals from three Gain blocks:
Set Output data type to
Bus: B_struct_type
.Select Output as nonvirtual bus.
Click OK.
6. In the dialog box of the other subordinate Bus Creator block:
Set Output data type to
Bus: C_struct_type
.Select Output as nonvirtual bus.
Click OK.
7. In the last Bus Creator block dialog box:
Set Output data type to
Bus: A_struct_type
.Select Output as nonvirtual bus.
Click OK.
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 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.
10. For the added signal, set Storage Class to ExportedGlobal
.
11. 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
.
12. 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
.
Combine Techniques to Work Around Limitations
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 buses 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 atModel 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.
Arrays of Structures
You can further package multiple consistent buses 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.
Structure Padding
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 (Embedded Coder).
Limitations
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 (Embedded Coder)).
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 toFlatStructure
), to set data defaults in the Code Mapping Editor.
See Also
Related Topics
- How Generated Code Stores Internal Signal, State, and Parameter Data
- Exchange Data Between External C/C++ Code and Simulink Model or Generated Code
- C Data Code Interface Configuration for Model Interface Elements (Embedded Coder)
- Control Data and Function Placement in Memory by Inserting Pragmas (Embedded Coder)
- Flexible Storage Class for Different Model Hierarchy Contexts (Embedded Coder)
- Composite Interface Guidelines