Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Basic Types

Numbers, bits, and truth values. Every other type in the language is built from these.

Integers

Eight integer types, four signed and four unsigned:

TypeSizeRange
SINT8 bit-128 to 127
USINT8 bit0 to 255
INT16 bit-32 768 to 32 767
UINT16 bit0 to 65 535
DINT32 bit-2 147 483 648 to 2 147 483 647
UDINT32 bit0 to 4 294 967 295
LINT64 bit-9 223 372 036 854 775 808 to 9 223 372 036 854 775 807
ULINT64 bit0 to 18 446 744 073 709 551 615

DINT is the type to reach for. It is the type that the compiler gives to a whole-number literal, and only a literal too large for 32 bits becomes a LINT.

A literal can be written in another base, and _ between two digits groups them:

i1: DINT := 42;
i2: DINT := 2#101010;     (* binary *)
i3: DINT := 8#52;         (* octal *)
i4: DINT := 16#2A;        (* hexadecimal *)
i5: DINT := 1_000_000;

Integer division cuts towards zero and never produces a fraction: 7 / 2 is 3 and -7 / 2 is -3. MOD gives the rest of that division, so 7 MOD 2 is 1 and -7 MOD 2 is -1.

BOOL

BOOL holds TRUE or FALSE and takes one byte. It is the type of every condition in IF, WHILE, and UNTIL.

An integer in a condition is accepted and counts as true when it is not zero. The compiler warns and asks you to add an = or a <> operator, so that the test says what it means:

IF level THEN        (* accepted, with a warning *)
IF level <> 0 THEN   (* the same test, and it says so *)

Bit strings

Four types that mean “a sequence of bits”, not “a number”:

TypeSize
BYTE8 bit
WORD16 bit
DWORD32 bit
LWORD64 bit

Use them for flags, masks, and values that come from hardware. AND, OR, XOR, and NOT work on them bit by bit, and the hardware access chapter shows how to read a single bit out of one.

VAR
    flags: BYTE := 2#0000_1100;
    mask: BYTE := 16#0F;
    result: BYTE;
END_VAR

result := flags AND mask;   (* 2#0000_1100 *)

Reals

REAL is 32 bits wide and LREAL is 64. A literal with a decimal point or an exponent is a real:

r1: REAL := 1.5;
r2: LREAL := 1.0e-9;

A REAL keeps about seven decimal digits, which is less than a DINT needs. A large whole number does not survive a trip through a REAL: 123456789 comes back as 123456792.

Conversion between types

The compiler converts a value to a wider type of the same family by itself:

VAR
    small: INT := 300;
    big: DINT;
END_VAR

big := small;   (* fine, every INT fits in a DINT *)

The other direction also compiles, but the value can change, so the compiler warns:

VAR
    small: INT := 300;
    tiny: SINT;
END_VAR

tiny := small;   (* warning[E067]: Implicit downcast from 'INT' to 'SINT'. *)

Here tiny keeps the low eight bits of 300, which is 44. Write the conversion yourself when the narrowing is intended. The standard library has a function for every pair of types, named after them:

tiny := INT_TO_SINT(small);

Note

The conversion functions live in the standard library, so a project that calls one, for example INT_TO_SINT, must link iec61131std. See Linking and Libraries.

A value also crosses between the two families. An integer becomes a real without any warning, although a large DINT loses digits on the way. A real becomes an integer with the same downcast warning, and the fraction is cut off. Two standard functions say which result you want:

VAR
    r: REAL := 2.7;
    n: DINT;
END_VAR

n := REAL_TO_DINT(r);   (* 3, the nearest whole number *)
n := TRUNC_DINT(r);     (* 2, the fraction is cut off *)

A type name with # in front of a value states the type of that value. On a literal it decides how the literal is read, and on a variable it converts:

x := DINT#16#2A;    (* the literal 16#2A, as a DINT *)
y := DINT#small;    (* small, converted to DINT *)

What’s next

The next chapter is about text: the two string types, their length, and what you can do with them.