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.

GoalTechnique

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.

  • When you generate nonreetrant, single-instance code by setting the model configuration parameter Code interface packaging to Nonreusable function, create flat, global structure variables by applying the built-in storage class Struct. Alternatively, use example storage classes created by Quick Start tool, ParamStruct and SignalStruct, or create and apply your own structured storage class.

  • When you generate multi-instance (reentrant) code from a model or a component, for example by setting Code interface packaging to a value other than Nonreusable function, in the Code Mappings editor, you cannot use the built-in storage class Struct or a structured storage class that you create in a package. Instead, create your own structured storage class by using an Embedded Coder Dictionary. If you use the Embedded Coder Quick Start tool to prepare the model for code generation (see Generate Code by Using the Quick Start Tool), you can use example storage classes ParamStruct and SignalStruct.

  • You cannot use this technique to aggregate global data stores or global parameters (which include parameter objects that you store in the base workspace or a data dictionary). For these kinds of data, use other techniques to create structures.

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 Simulink.Bus object that represents the structure type that you want. Use the bus object to set the data types of nonvirtual bus signals and parameter structures in your model.

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 Simulink.Bus object that represents the structure type that you want. If your external code already defines the type, use the Simulink.importExternalCTypes function to generate the bus object. Use the bus object to set the data types of nonvirtual bus signals and parameter structures in your model. For an example, see Exchange Structured and Enumerated Data Between Generated and External Code.

Reduce the number of arguments (formal parameters) for generated functions.

  • To reduce the number of arguments for the entry-point functions of the model from which you generate code, such as model_step, see Reduce Number of Arguments by Using Structures.

  • To reduce the number of arguments for the entry-point functions of a referenced model, in the referenced model:

  • To reduce the number of arguments for the entry-point functions of a masked, reentrant subsystem, aggregate mask parameters into a custom structure.

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.

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.

CapabilityDefault Application of Structured Storage ClassDirect Application of Structured Storage Class Nonvirtual Buses and Parameter Structures
Aggregate new data items into a structure by default

Yes

NoNo
Prevent elimination of the target data by optimizations (specify that the data appear in the generated code)

No

YesOnly 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

YesNo
Place signal, state, and parameter data in the same structureNoYesNo
Include state data in a structureYesYesNo
Organize structures into nested structuresNoNoYes
Organize structures into an array of structuresNoNoYes
Control name of structure type

Yes

Yes, but the type name derives from the variable name, which you specifyYes
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

NoYes
Requires Embedded CoderYesYesNo

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. To create your own storage class by using an Embedded Coder Dictionary, see Create Code Definitions for Use in the Code Mappings Editor.

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. For more information about applying storage classes, see Organize Parameter Data into a Structure by Using Struct Storage Class.

Nonvirtual Buses and Parameter Structures

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

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 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

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 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.

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 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.

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 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.

Arrays of Structures

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.

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.

Limitations

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

See Also

Related Topics