Skip to content

Derived types

Derived types are user-defined types built on top of the elementary data types. They are declared inside a TYPE … END_TYPE block and can then be used anywhere an elementary type is allowed.

TYPE
Temperature : REAL; // simple alias
Percent : INT(0..100); // subrange
Color : (RED, GREEN, BLUE); // enumeration
Point : STRUCT // structure
x : REAL;
y : REAL;
END_STRUCT;
END_TYPE

A single TYPE … END_TYPE block may contain any number of type declarations.

A simple derived type gives a new name to an existing type, optionally with a default initial value.

TYPE
Counter : DINT := 0;
END_TYPE

A subrange restricts an integer type to a closed range low..high.

TYPE
Percent : INT(0..100);
Level : INT(0..100) := 50; // with initial value
END_TYPE

The base type must be an integer type (SINT, INT, DINT, LINT or their unsigned forms). The bounds are constant expressions.

An enumeration declares a fixed set of named values. Values may be implicit (assigned in order) or explicit.

TYPE
Mode : (MANUAL, AUTO, SERVICE); // implicit
ErrorCode : (NONE := 0, WARN := 10, FATAL := 100); // explicit values
Gear : INT (FIRST, SECOND, THIRD) := SECOND; // typed + default
END_TYPE
  • Members can be given explicit values with :=.
  • The enumeration can specify an underlying integer type and a default member.
  • Reference a member as Mode#AUTO when disambiguation is needed.

A STRUCT groups named elements of possibly different types.

TYPE
Motor : STRUCT
speed : REAL;
running : BOOL := FALSE;
name : STRING[32];
END_STRUCT;
END_TYPE

Access elements with dot notation:

VAR
pump : Motor;
END_VAR
pump.speed := 1500.0;
IF pump.running THEN ... END_IF

STRUCT OVERLAP lays all elements at the same memory location (a union), so the elements share storage instead of being placed sequentially.

TYPE
Word2Bytes : STRUCT OVERLAP
asWord : WORD;
asBytes : ARRAY[0..1] OF BYTE;
END_STRUCT;
END_TYPE

Individual struct elements may carry a JSON serialization pragma — see pragmas.

An array is an indexed collection of elements of a single type. The index range is given as low..high.

TYPE
Buffer : ARRAY[0..9] OF INT; // 10 elements, indices 0..9
END_TYPE

Separate the dimension ranges with commas.

TYPE
Matrix : ARRAY[1..3, 1..3] OF REAL; // 3 x 3
END_TYPE
VAR
m : Matrix;
END_VAR
m[2, 3] := 1.0;

Use a bracketed initializer list. The count(value) shorthand repeats a value.

TYPE
Flags : ARRAY[0..4] OF BOOL := [TRUE, FALSE, TRUE, FALSE, TRUE];
Zeros : ARRAY[0..9] OF INT := [10(0)]; // ten zeros
Mixed : ARRAY[0..4] OF INT := [1, 2, 3(7)]; // 1, 2, 7, 7, 7
END_TYPE

ARRAY[*] declares a conformant array whose bounds are not fixed at declaration. This is used for VAR_IN_OUT parameters that accept arrays of any size; the actual bounds are queried at runtime with LOWER_BOUND / UPPER_BOUND.

FUNCTION SumAll : REAL
VAR_IN_OUT
data : ARRAY[*] OF REAL;
END_VAR
VAR
i : DINT;
END_VAR
SumAll := 0.0;
FOR i := LOWER_BOUND(data, 1) TO UPPER_BOUND(data, 1) DO
SumAll := SumAll + data[i];
END_FOR;
END_FUNCTION

STRING and WSTRING may carry a maximum length in square brackets (or parentheses). The length is a constant and bounds the storage reserved for the string.

TYPE
Name : STRING[32]; // up to 32 single-byte characters
Label : WSTRING[16]; // up to 16 double-byte characters
END_TYPE
VAR
title : STRING[64] := 'Untitled';
END_VAR

A reference holds the address of another variable. Declare a reference type with REF_TO.

TYPE
MotorRef : REF_TO Motor;
END_TYPE
VAR
pump : Motor;
handle : REF_TO Motor; // reference declared inline
END_VAR
  • REF(x) — take a reference to variable x.
  • r^ — dereference: access the value r points to.
  • NULL — the null reference (the default initial value of any reference).
handle := REF(pump); // point at pump
handle^.speed := 1200.0; // write through the reference
IF handle <> NULL THEN
...
END_IF

The ?= operator performs a reference assignment attempt: it assigns the reference only if the runtime types are compatible, and otherwise leaves the target as NULL. Use it for safe down-casts along an inheritance hierarchy.

VAR
base : REF_TO BaseFB;
derived : REF_TO DerivedFB;
END_VAR
derived ?= base; // succeeds only if base actually refers to a DerivedFB
IF derived <> NULL THEN
...
END_IF