Main Content

Manage Replacement of Simulink Data Types in Generated Code

You can manage the replacement of Simulink® data types in generated code by using:

Using Data Type Replacement Configuration Parameters

You can use the Data type replacement configuration parameter to control the replacement of Simulink data types in generated code:

  • If you set the parameter to Use coder typedefs, the code generator creates the header file rtwtypes.h and generates data types that are based on the C89 language standard. See Simulink Coder Data Types in Generated Code

    The rtwtypes.h file defines the data types through typedef statements that build on C primitive types, for example, float and short.

  • If you set the parameter to Use C data types with fixed-width integers, the generated code uses data types from the C99 language standard, which includes definitions from stdint.h and stdbool.h. See C99 Data Types in Generated Code.

    The generated code does not include the rtwtypes.h header file. The file rtwtypes.h is generated in some cases because it might be needed by static source code located under matlabroot. Additionally, if you use custom code that requires Simulink Coder™ data type definitions, you can force the generation of rtwtypes.h by selecting the Coder typedefs compatibility check box.

If you also select the Specify custom data type names check box, you can specify replacement names for the data types. See Specify Custom Names Using Data Replacement Type Pane.

C99 Data Types in Generated Code

When the Data type replacement configuration parameter is set to Use C data types with fixed-width integers, the code generator replaces Simulink data types with C99 data types as shown in this table.

Simulink NameCode Generation Name

double

double

single

float

int32

int32_t

int16

int16_t

int8

int8_t

uint32

uint32_t

uint16

uint16_t

uint8

uint8_t

boolean

bool

int

int

uint

unsigned int

char

char

uint64

uint64_t

int64

int64_t

Simulink Coder Data Types in Generated Code

When the Data type replacement configuration parameter is set to Use coder typedefs, the code generator replaces Simulink data types with Simulink Coder data types as shown in this table.

Simulink NameCode Generation Name

double

real_T

single

real32_T

int32

int32_T

int16

int16_T

int8

int8_T

uint32

uint32_T

uint16

uint16_T

uint8

uint8_T

boolean

boolean_T

int

int_T

uint

uint_T

int

char_T

uint64

uint64_T

int64

int64_T

Specify Custom Names Using Data Replacement Type Pane

You can specify custom names for the generated data types. For example, to change the name of the Simulink Coder data type int8_T to myType, create a Simulink.AliasType object. In the Command Window, enter:

myType = Simulink.AliasType;

Set the BaseType property to the Simulink data type that corresponds to the generated data type name. In this example, int8 corresponds to int8_T.

myType.BaseType = 'int8';

Specify the header file that contains the definition of the data type.

myType.HeaderFile = "my_header.h"
writelines("typedef signed char myType;", "my_header.h")

In the Configuration Parameters dialog box, select the Specify custom data type names check box. Then, in the Replacement Name field that corresponds to int8, enter myType.

For an example, see Replace and Rename Simulink Coder Data Types to Conform to Coding Standards.

Replace Implementation-Dependent Types with the Same Type Name

Some Simulink Coder type names map to C primitives that are implementation-dependent. For example, the Simulink Coder type int_T maps to the C type int, whose bit length depends on the native integer size of your target hardware. Other implementation-dependent types include boolean_T, char_T, and uint_T.

For more readable, simpler code, you can use the same type name to replace multiple Simulink Coder types of the same size. For example, if the native integer size of your hardware is 32 bits, you can replace int_T and int32_T with the same type name, say, myInt.

  1. Configure your target hardware settings in Configuration Parameters > Hardware Implementation.

  2. Create a Simulink.AliasType object named myInt. In this case, because int_T and int32_T represent a 32-bit signed integer, set BaseType to int32.

    myInt = Simulink.AliasType('int32')

  3. Specify the header file that contains the definition of the data type.

    myInt.HeaderFile = "my_header.h"
    writelines("typedef signed char myInt;", "my_header.h")

  4. In the Replacement Name fields for both data types, specify myInt.

Note

Many-to-one data type replacement does not support the char (char_T) built-in data type. Use char only in one-to-one data type replacements.

Many-to-one data type replacement is not supported for Simulink Coder data types of different sizes.

Using Data Type Objects for Block Diagram Signals

You can specify data types for block diagram signals by using the Model Editor and data type objects, for example, Simulink.AliasType and Simulink.NumericType.

Specify Custom Names Using Model Editor

You can specify custom names for the generated data types. For example, to rename the Simulink Coder data type int8_T, create a Simulink.AliasType object, specifying a name that you want the generated code to use. In the Command Window, enter:

myType = Simulink.AliasType;

Set the BaseType property to the Simulink data type that corresponds to the generated data type name. In this example, int8 corresponds to int8_T.

myType.BaseType = 'int8';

Specify the header file that contains the definition of the data type.

myType.HeaderFile = "my_header.h"
writelines("typedef signed char myType;", "my_header.h")

Then, in the Model Editor, use the Simulink.AliasType object to specify the data type of an individual signal, that is, a block output, or block parameter. By default, due to data type propagation and inheritance (see Data Type Inheritance Rules), the signals, states, and parameters of other downstream blocks typically inherit the same data type. Optionally, you can configure upstream blocks to inherit the type (Inherit: Inherit via back propagation) or stop the propagation at an arbitrary block by specifying a noninherited data type setting.

For an example, see Create Data Type Alias in the Generated Code.

This table summarizes two techniques you can use for naming data types in generated code.

Naming ObjectiveTechnique
Configure the code generator to define a particular data item, such as a variable, by using a specific, meaningful type name.

In the model, locate the data item that corresponds to the variable. For example, trace from the code generation report to the model. Use the name of the Simulink.AliasType object to set the data type of the item.

If necessary, to prevent other data items in upstream and downstream blocks from using the same type name, configure those items to use a data type setting that is not inherited. By default, most signals use the inherited type Inherit: Inherit via internal rule.

Use the same type name for multiple signals and other data items in a data path, which is a series of connected blocks.

In the model, use the name of a Simulink.AliasType object to set the data type of one of the signals in the path, for example, a root-level Inport block or a Constant block. For example, if the path begins with an Inport block at the root level of the model, you can specify the type in that block. By default, due to data type propagation, the data items in the other blocks typically inherit the same type.

Usually, no matter where on the data path you specify the type, downstream data items inherit the type. You can configure upstream data items to inherit the type, too. Consider specifying the type in a block that you do not expect to remove or change frequently.

Define Abstract Numeric Types and Rename Types

This model shows user-defined types, consisting of numeric and alias types. Numeric types allow you to define abstract numeric types, which is particularly useful for fixed-point types. Alias types allow you to rename types, which allows you create a relationship for types.

Explore Example Model

Open the example model and configure it to show the generated names of blocks.

load_system('UserDefinedDataTypes')
set_param('UserDefinedDataTypes','HideAutomaticNames','off')
open_system('UserDefinedDataTypes')

Key Features of User-Defined Types

  • Displayed and propagated on signal lines

  • Used to parameterize a model by type (e.g., In1 specifies its Output data type as ENG_SPEED)

  • Types with a common ancestor can be mixed, whereby the common ancestor is propagated (e.g., output of Sum1)

  • Intrinsically supported by the Simulink Model Explorer

  • Include an optional header file attribute that is ideal for importing legacy types (ignored for GRT targets)

  • Types used in the generated code (ignored for GRT targets)

Instructions

  1. Inspect the user-defined types in the Model Explorer by double-clicking the first yellow button below.

  2. Inspect the replacement data type mapping by double-clicking the second yellow button below.

  3. Compile the diagram to display the types in this model (Debug > Update Model > Update Model or Ctrl+D).

  4. Generate code with the blue button below and inspect model files to see how user-defined types appear in the generated code.

  5. Modify the attributes of ENG_SPEED and ENG_SPEED_OFFSET and repeat steps 1-4.

Notes

  • User-defined types are a feature of Simulink that facilitate parameterization of the data types in a model. Embedded Coder preserves alias data type names (e.g., ENG_SPEED) in the generated code, whereas Simulink Coder implements user-defined types as their base type (e.g., real32_T).

  • Embedded Coder also enables you to replace the built-in data types with user-defined data types in the generated code.

Control Names of Structure Types

To control the names of the standard structures that Simulink Coder creates by default to store data (model_P for parameter data, for example), use Configuration Parameters > Code Generation > Identifiers > Global types to specify a naming rule. For more information, see Identifier Format Control.

When you use nonvirtual buses and parameter structures to aggregate signals and block parameters into a custom structure in the generated code, control the name of the structure type by creating a Simulink.Bus object. For more information, see Organize Data into Structures in Generated Code.

Generate Code That Reuses Data Types From External Code

To generate code that reuses a data type definition from your external C code, specify the data scope of the corresponding data type object or enumeration in Simulink as Imported. With this setting, the generated code includes (#include) the definition from your code. For more information about controlling the file placement of a custom data type, see Control File Placement of Custom Data Types.

Instead of creating individual data type objects and enumerated types, and then configuring them, consider creating the objects and types by using the Simulink.importExternalCTypes function. By default, the function configures the new objects and types so that the generated code imports (reuses) the type definitions from your code. You can then use the objects and types to set data types in a model and to configure data type replacements. For more information, see Simulink.importExternalCTypes and Exchange Structured and Enumerated Data Between Generated and External Code.

Create Data Type Alias in the Generated Code

This example shows how to configure the generated code to use a data type name (typedef) that you specify.

Export Type Definition

When you integrate code generated from a model with code from other sources, your model code can create an exported typedef statement. Therefore, all of the integrated code can use the type. This example shows how to export the definition of a data type to a generated header file.

Create a Simulink.AliasType object named mySingleAlias that acts as an alias for the built-in data type single.

mySingleAlias = Simulink.AliasType('single');

Configure the object to export its definition to a header file called myHdrFile.h.

mySingleAlias.DataScope = 'Exported';
mySingleAlias.HeaderFile = 'myHdrFile.h';

Open the model ConfigurationInterface.

open_system('ConfigurationInterface')

Configure the model to show the generated names of blocks.

set_param('ConfigurationInterface','HideAutomaticNames','off')

On the Modeling tab, click Model Data Editor.

In the model, select the Inport block labeled In1.

Use the Data Type column to set the data type to mySingleAlias.

set_param('ConfigurationInterface/In1','OutDataTypeStr','mySingleAlias')

Configure In1 to use default storage.

In the C Code tab, select Code Interface > Default Code Mappings.

In the Code Mappings editor, under Inports and Outports, select category Inports. Set the default storage class to Default.

On the Inports tab, set Storage Class to Model default.

cm = coder.mapping.api.get('ConfigurationInterface');
setDataDefault(cm,'Inports','StorageClass','Default');
setInport(cm,'In1','StorageClass','Model default');

Generate code from the model.

slbuild('ConfigurationInterface')
### Starting build procedure for: ConfigurationInterface
### Successful completion of code generation for: ConfigurationInterface

Build Summary

Top model targets:

Model                   Build Reason                                         Status           Build Duration
============================================================================================================
ConfigurationInterface  Information cache folder or artifacts were missing.  Code generated.  0h 0m 12.028s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 13.208s

In the code generation report, view the file ConfigurationInterface_types.h. The code creates a #include directive for the generated file myHdrFile.h.

file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface_types.h');
coder.example.extractLines(file,'#include "myHdrFile.h"',...
    '#include "myHdrFile.h"',1,1)
#include "myHdrFile.h"

View the file myHdrFile.h. The code uses the identifier mySingleAlias as an alias for the data type real32_T. By default, generated code represents the Simulink data type single by using the identifier real32_T.

The code also provides a macro guard of the form filename_h_. When you export a data type definition to integrate generated code with code from other sources, you can use macro guards of this form to prevent unintentional identifier clashes.

file = fullfile('slprj','ert','_sharedutils','myHdrFile.h');
coder.example.extractLines(file,'#ifndef myHdrFile_h_',...
    ' * File trailer for generated code.',1,0)
#ifndef myHdrFile_h_
#define myHdrFile_h_
#include "rtwtypes.h"

typedef real32_T mySingleAlias;
typedef creal32_T cmySingleAlias;

#endif                                 /* myHdrFile_h_ */

/*

View the file ConfigurationInterface.h. The code uses the data type alias mySingleAlias to define the structure field input1, which corresponds to the Inport block labeled In1.

file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface.h');
coder.example.extractLines(file,...
    '/* External inputs (root inport signals with default storage) */',...
    '} ExtU_ConfigurationInterface_T;',1,1)
/* External inputs (root inport signals with default storage) */
typedef struct {
  mySingleAlias input1;                /* '<Root>/In1' */
  MYTYPE input2;                       /* '<Root>/In2' */
  MYTYPE input3;                       /* '<Root>/In3' */
  MYTYPE input4;                       /* '<Root>/In4' */
} ExtU_ConfigurationInterface_T;

Import Type Definition

When you integrate code generated from a model with code from other sources, to avoid redundant typedef statements, you can import a data type definition from the external code. This example shows how to import your own definition of a data type from a header file that you create.

Use a text editor to create a header file to import. Name the file ex_myImportedHdrFile.h. Place it in your working folder. Copy the following code into the file.

#ifndef HEADER_myImportedHdrFile_h_
#define HEADER_myImportedHdrFile_h_

typedef float myTypeAlias;

#endif 

The code uses the identifier myTypeAlias to create an alias for the data type float. The code also uses a macro guard of the form HEADER_filename_h. When you import a data type definition to integrate generated code with code from other sources, you can use macro guards of this form to prevent unintentional identifier clashes.

At the command prompt, create a Simulink.AliasType object named myTypeAlias that creates an alias for the built-in type single. The Simulink data type single corresponds to the C data type float.

myTypeAlias = Simulink.AliasType('single');

Configure the object so that generated code imports the type definition from the header file ex_myImportedHdrFile.h.

myTypeAlias.DataScope = 'Imported';
myTypeAlias.HeaderFile = 'ex_myImportedHdrFile.h';

Open the model ConfigurationInterface.

open_system('ConfigurationInterface')

On the Modeling tab, click Model Data Editor.

In the model, select the Inport block labeled In1.

Use the Data Type column to set the data type to myTypeAlias.

set_param('ConfigurationInterface/In1','OutDataTypeStr','myTypeAlias')

Generate code from the model.

slbuild('ConfigurationInterface')
### Starting build procedure for: ConfigurationInterface
### Successful completion of code generation for: ConfigurationInterface

Build Summary

Top model targets:

Model                   Build Reason                     Status           Build Duration
========================================================================================
ConfigurationInterface  Generated code was out of date.  Code generated.  0h 0m 9.4426s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 10.999s

In the code generation report, view the file ConfigurationInterface_types.h. The code creates a #include directive for your header file ex_myImportedHdrFile.h.

file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface_types.h');
coder.example.extractLines(file,'#include "ex_myImportedHdrFile.h',...
    '/* Forward declaration for rtModel */',1,0)
#include "ex_myImportedHdrFile.h"
#include "MYTYPE.h"
#ifndef DEFINED_TYPEDEF_FOR_Table1_Type_
#define DEFINED_TYPEDEF_FOR_Table1_Type_

typedef struct {
  MYTYPE BP[11];
  MYTYPE Table[11];
} Table1_Type;

#endif

#ifndef DEFINED_TYPEDEF_FOR_Table2_Type_
#define DEFINED_TYPEDEF_FOR_Table2_Type_

typedef struct {
  MYTYPE BP1[3];
  MYTYPE BP2[3];
  MYTYPE Table[9];
} Table2_Type;

#endif
#endif                                 /* ConfigurationInterface_types_h_ */

/*
 * File trailer for generated code.
 *
 * [EOF]
 */

View the file ConfigurationInterface.h. The code uses the data type alias myTypeAlias to define the structure field input1, which corresponds to the Inport block labeled In1.

file = fullfile('ConfigurationInterface_ert_rtw','ConfigurationInterface.h');
coder.example.extractLines(file,...
    '/* External inputs (root inport signals with default storage) */',...
    '} ExtU_ConfigurationInterface_T;',1,1)
/* External inputs (root inport signals with default storage) */
typedef struct {
  myTypeAlias input1;                  /* '<Root>/In1' */
  MYTYPE input2;                       /* '<Root>/In2' */
  MYTYPE input3;                       /* '<Root>/In3' */
  MYTYPE input4;                       /* '<Root>/In4' */
} ExtU_ConfigurationInterface_T;

Display Base Data Types and Aliases on Model Diagram

When you display signal data types on the model diagram, you can choose to display aliases (such as myTypeAlias) and base data types (such as int16). To display aliases, on the Debug tab, select Information Overlays > Alias Data Types. To display the base types, select Information Overlays > Base Data Types. For more information, see Port Data Types.

Create a Named Fixed-Point Data Type in the Generated Code

This example shows how to create and name a fixed-point data type in generated code. You can use the name of the type to specify parameter and signal data types throughout a model and in generated code.

The example model FixedPointCodeGeneration uses fixed-point data types. So that you can more easily see the fixed-point data type in the generated code, in this example, you create a Simulink.Parameter object that appears in the code as a global variable.

Create a Simulink.AliasType object that defines a fixed-point data type. Name the object myFixType. The generated code uses the name of the object as a data type.

myFixType = Simulink.AliasType('fixdt(1,16,4)');

Open the model FixedPointCodeGeneration.

open_system('FixedPointCodeGeneration')

Configure the model to show the generated names of the blocks.

set_param('FixedPointCodeGeneration','HideAutomaticNames','off')

On the Modeling tab, click Model Data Editor.

In the Model Data Editor, select the Parameters tab.

In the model, select the Gain block.

In the Model Data Editor, for the row that represents the Gain parameter of the Gain block, in the Value column, specify myParam.

Click the action button (with three vertical dots) next to the parameter value. Select Create.

In the Create New Data dialog box, set Value to Simulink.Parameter(8). In this example, for more easily readable code, you set the parameter value to 8 instead of -3.2. Click Create. A Simulink.Parameter object named myParam appears in the base workspace. The object stores the real-world value 8, which the Gain block uses for the value of the Gain parameter.

In the Simulink.Parameter property dialog box, set Storage class to ExportedGlobal. Click OK. With this setting, myParam appears in the generated code as a separate global variable.

In the Model Data Editor, use the Data Type column to set the data type of the Gain parameter of the Gain block to myFixType.

On the Signals tab, use the Data Type column to set the data type of the Gain block output to myFixType.

Use the Data Type column to set the data type of the Conversion block output to myFixType.

Alternatively, you can use these commands at the command prompt to configure the blocks and create the object:

set_param('FixedPointCodeGeneration/Gain','Gain','myParam','OutDataTypeStr','myFixType',...
    'ParamDataTypeStr','myFixType')
myParam = Simulink.Parameter(8);
myParam.StorageClass = 'ExportedGlobal';
set_param('FixedPointCodeGeneration/Conversion','OutDataTypeStr','myFixType')

In the model, set Configuration Parameters > Code Generation > System target file to ert.tlc. With this setting, the code generator honors data type aliases such as myFixType.

set_param('FixedPointCodeGeneration','SystemTargetFile','ert.tlc')

Select the configuration parameter Generate code only.

set_param('FixedPointCodeGeneration','GenCodeOnly','on')

Generate code from the model.

slbuild('FixedPointCodeGeneration')
### Starting build procedure for: FixedPointCodeGeneration
### Successful completion of code generation for: FixedPointCodeGeneration

Build Summary

Top model targets:

Model                     Build Reason                                         Status           Build Duration
==============================================================================================================
FixedPointCodeGeneration  Information cache folder or artifacts were missing.  Code generated.  0h 0m 15.628s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 16.971s

In the code generation report, view the file FixedPointCodeGeneration_types.h. The code defines the type myFixType based on an integer type of the specified word length (16).

file = fullfile('FixedPointCodeGeneration_ert_rtw','FixedPointCodeGeneration_types.h');
coder.example.extractLines(file,'#ifndef DEFINED_TYPEDEF_FOR_myFixType_',...
    '/* Forward declaration for rtModel */',1,0)
#ifndef DEFINED_TYPEDEF_FOR_myFixType_
#define DEFINED_TYPEDEF_FOR_myFixType_

typedef int16_T myFixType;
typedef cint16_T cmyFixType;

#endif

View the file FixedPointCodeGeneration.c. The code uses the type myFixType, which is an alias of the integer type int16, to define the variable myParam.

file = fullfile('FixedPointCodeGeneration_ert_rtw','FixedPointCodeGeneration.c');
coder.example.extractLines(file,'myFixType myParam = 128;','myFixType myParam = 128;',1,1)
myFixType myParam = 128;               /* Variable: myParam

The stored integer value 128 of myParam is not the same as the real-world value 8 because of the scaling that the fixed-point data type myFixType specifies. For more information, see Scaling (Fixed-Point Designer) in the Fixed-Point Designer documentation.

The line of code that represents the Gain block applies a right bit shift corresponding to the fraction length specified by myFixType.

coder.example.extractLines(file,...
    'FixedPointCodeGeneration_Y.Out1 = (myFixType)((myParam * rtb_Conversion) >> 4);',...
    'FixedPointCodeGeneration_Y.Out1 = (myFixType)((myParam * rtb_Conversion) >> 4);',1,1)
  FixedPointCodeGeneration_Y.Out1 = (myFixType)((myParam * rtb_Conversion) >> 4);

Rename Data Type Object

To rename a data type object such as Simulink.AliasType or Simulink.Bus after you create it (for example, to rename an alias when coding standards change or when you encounter a naming conflict), you can allow Simulink to rename the object and correct all of the references to the object that appear in a model or models. In the Model Explorer, right-click the variable and select Rename All. For more information, see Rename Variables.

Display Signal Data Types on Block Diagram

For readability, you can display signal data types directly on a block diagram. When you use custom names for primitive data types, you can choose to display the custom name (the alias), the underlying primitive, or both. See Port Data Types.

Data Type Replacement Limitations

  • You cannot configure the generated code to use these custom C data types:

    • Array types

    • Pointer types

    • const or volatile types

  • You cannot configure the generated code to use generic C primitive types such as int and short.

When you set Data type replacement to Use C data types with fixed-width integers, these limitations apply:

  • You cannot generate code for third-party hardware workflows that use Embedded Coder® support packages.

  • In generated C++ code, statements that include the header files stdint.h and stdbool.h violate MISRA™ C++:2008 rule 18-0-1.

  • If the model includes Simscape™ blocks, some of the generated source files might contain #include "rtwtypes.h". Generated code from Simscape blocks is not intended for production deployment. The build process can compile the generated code because the code generator creates a rtwtypes.h file for continuous-time models.

When you set Data type replacement to Use coder typedefs and select the Specify custom data type names configuration parameter, these limitations apply:

  • Data type replacement does not support multiple levels of mapping. Each replacement data type name maps directly to one or more built-in data types.

  • Data type replacement is not supported for simulation target code generation for referenced models.

  • Code generation performs data type replacements while generating .c, .cpp, and .h files. Code generation places these files in build folders (including top and referenced model build folders) and in the _sharedutils folder. Exceptions are as follows:

    rtwtypes.h
    multiword_types.h
    model_reference_types.h
    builtin_typeid_types.h
    model_sf.c or .cpp (ERT S-function wrapper)
    model_dt.h (C header file supporting external mode)
    model_capi.c or .cpp
    model_capi.h
  • Data type replacement is not supported for complex data types.

  • Many-to-one data type replacement is not supported for the char data type. Attempting to use char as part of a many-to-one mapping to a custom data type represents a violation of the MISRA C™ specification. For example, if you map char (char_T) and either int8 (int8_T) or uint8 (uint8_T) to the same replacement type, the result is a MISRA C violation. If you try to generate C++ code, the code generator makes invalid implicit type casts, resulting in compile-time errors. Use char only in one-to-one data type replacements.

    Many-to-one data type replacement is not supported for Simulink Coder data types of different sizes. For more information, see Replace Implementation-Dependent Types with the Same Type Name.

  • For ERT S-functions, replace the boolean data type with only an 8-bit integer, int8, or uint8.

  • Set the DataScope property of a Simulink.AliasType object to Auto (default) or Imported.

Related Topics