Type Conversions

IEC 61131-3 defines a set of type conversion functions that convert values between data types. Each function follows the naming pattern <source>_TO_<target>.

Conversion Categories

Integer Widening

Conversions from a smaller integer type to a larger integer type. These conversions are always safe — no data is lost.

Function

Description

SINT_TO_INT

8-bit to 16-bit signed

SINT_TO_DINT

8-bit to 32-bit signed

SINT_TO_LINT

8-bit to 64-bit signed

INT_TO_DINT

16-bit to 32-bit signed

INT_TO_LINT

16-bit to 64-bit signed

DINT_TO_LINT

32-bit to 64-bit signed

USINT_TO_UINT

8-bit to 16-bit unsigned

USINT_TO_UDINT

8-bit to 32-bit unsigned

USINT_TO_ULINT

8-bit to 64-bit unsigned

UINT_TO_UDINT

16-bit to 32-bit unsigned

UINT_TO_ULINT

16-bit to 64-bit unsigned

UDINT_TO_ULINT

32-bit to 64-bit unsigned

Integer Narrowing

Conversions from a larger integer type to a smaller integer type. These conversions may lose data if the value exceeds the range of the target type.

Function

Description

INT_TO_SINT

16-bit to 8-bit signed

DINT_TO_SINT

32-bit to 8-bit signed

DINT_TO_INT

32-bit to 16-bit signed

LINT_TO_SINT

64-bit to 8-bit signed

LINT_TO_INT

64-bit to 16-bit signed

LINT_TO_DINT

64-bit to 32-bit signed

UINT_TO_USINT

16-bit to 8-bit unsigned

UDINT_TO_USINT

32-bit to 8-bit unsigned

UDINT_TO_UINT

32-bit to 16-bit unsigned

ULINT_TO_USINT

64-bit to 8-bit unsigned

ULINT_TO_UINT

64-bit to 16-bit unsigned

ULINT_TO_UDINT

64-bit to 32-bit unsigned

Signed/Unsigned Conversions

Conversions between signed and unsigned integer types of the same or different sizes.

Function

Description

SINT_TO_USINT

Signed to unsigned 8-bit

INT_TO_UINT

Signed to unsigned 16-bit

DINT_TO_UDINT

Signed to unsigned 32-bit

LINT_TO_ULINT

Signed to unsigned 64-bit

USINT_TO_SINT

Unsigned to signed 8-bit

UINT_TO_INT

Unsigned to signed 16-bit

UDINT_TO_DINT

Unsigned to signed 32-bit

ULINT_TO_LINT

Unsigned to signed 64-bit

Integer to Real

Conversions from integer types to floating-point types. Large integer values may lose precision when converted to REAL.

Function

Description

SINT_TO_REAL

8-bit signed to single-precision

INT_TO_REAL

16-bit signed to single-precision

DINT_TO_REAL

32-bit signed to single-precision

LINT_TO_REAL

64-bit signed to single-precision

SINT_TO_LREAL

8-bit signed to double-precision

INT_TO_LREAL

16-bit signed to double-precision

DINT_TO_LREAL

32-bit signed to double-precision

LINT_TO_LREAL

64-bit signed to double-precision

Real to Integer

Conversions from floating-point types to integer types. The fractional part is truncated.

Function

Description

REAL_TO_SINT

Single-precision to 8-bit signed

REAL_TO_INT

Single-precision to 16-bit signed

REAL_TO_DINT

Single-precision to 32-bit signed

REAL_TO_LINT

Single-precision to 64-bit signed

LREAL_TO_SINT

Double-precision to 8-bit signed

LREAL_TO_INT

Double-precision to 16-bit signed

LREAL_TO_DINT

Double-precision to 32-bit signed

LREAL_TO_LINT

Double-precision to 64-bit signed

Real to Real

Conversions between floating-point types.

Function

Description

REAL_TO_LREAL

Single-precision to double-precision

LREAL_TO_REAL

Double-precision to single-precision

Boolean Conversions

Conversions between BOOL and integer types. FALSE converts to 0, TRUE converts to 1. For the reverse direction, 0 converts to FALSE and any non-zero value converts to TRUE.

Function

Description

BOOL_TO_SINT

Boolean to 8-bit signed

BOOL_TO_INT

Boolean to 16-bit signed

BOOL_TO_DINT

Boolean to 32-bit signed

BOOL_TO_LINT

Boolean to 64-bit signed

BOOL_TO_USINT

Boolean to 8-bit unsigned

BOOL_TO_UINT

Boolean to 16-bit unsigned

BOOL_TO_UDINT

Boolean to 32-bit unsigned

BOOL_TO_ULINT

Boolean to 64-bit unsigned

SINT_TO_BOOL

8-bit signed to Boolean

INT_TO_BOOL

16-bit signed to Boolean

DINT_TO_BOOL

32-bit signed to Boolean

LINT_TO_BOOL

64-bit signed to Boolean

USINT_TO_BOOL

8-bit unsigned to Boolean

UINT_TO_BOOL

16-bit unsigned to Boolean

UDINT_TO_BOOL

32-bit unsigned to Boolean

ULINT_TO_BOOL

64-bit unsigned to Boolean

Time/Duration Conversions

Conversions between time duration types (TIME, LTIME) and numeric or bit string types. The underlying value is the duration in milliseconds.

Function

Description

TIME_TO_DINT

Duration to 32-bit signed

TIME_TO_INT

Duration to 16-bit signed

TIME_TO_REAL

Duration to single-precision float

TIME_TO_DWORD

Duration to 32-bit unsigned word

DINT_TO_TIME

32-bit signed to duration

DWORD_TO_TIME

32-bit unsigned word to duration

LTIME_TO_LINT

Long duration to 64-bit signed

LTIME_TO_LWORD

Long duration to 64-bit unsigned word

LINT_TO_LTIME

64-bit signed to long duration

All combinations of TIME/LTIME with signed integers, unsigned integers, real types, and bit string types are supported.

Date Conversions

Conversions between date types (DATE, LDATE) and numeric or bit string types. The underlying value is seconds since 1970-01-01.

Function

Description

DATE_TO_DWORD

Date to 32-bit unsigned word

DATE_TO_UDINT

Date to 32-bit unsigned integer

DWORD_TO_DATE

32-bit unsigned word to date

LDATE_TO_LWORD

Long date to 64-bit unsigned word

All combinations of DATE/LDATE with signed integers, unsigned integers, real types, and bit string types are supported.

Time-of-Day Conversions

Conversions between time-of-day types (TOD/TIME_OF_DAY, LTOD/LTIME_OF_DAY) and numeric or bit string types. The underlying value is milliseconds since midnight for both TOD and LTOD; LTOD is the wider type, not the higher-resolution one.

Function

Description

TOD_TO_DWORD

Time-of-day to 32-bit unsigned word

TOD_TO_UDINT

Time-of-day to 32-bit unsigned integer

DWORD_TO_TOD

32-bit unsigned word to time-of-day

LTOD_TO_LWORD

Long time-of-day to 64-bit unsigned word

Both short aliases (TOD, LTOD) and full names (TIME_OF_DAY, LTIME_OF_DAY) are supported. All combinations with signed integers, unsigned integers, real types, and bit string types are supported.

Date-and-Time Conversions

Conversions between date-and-time types (DT/DATE_AND_TIME, LDT/LDATE_AND_TIME) and numeric or bit string types. The underlying value is seconds since 1970-01-01 for both DT and LDT; LDT is the wider type, not the higher-resolution one.

Function

Description

DT_TO_DWORD

Date-and-time to 32-bit unsigned word

DT_TO_UDINT

Date-and-time to 32-bit unsigned integer

DWORD_TO_DT

32-bit unsigned word to date-and-time

LDT_TO_LWORD

Long date-and-time to 64-bit unsigned word

Both short aliases (DT, LDT) and full names (DATE_AND_TIME, LDATE_AND_TIME) are supported. All combinations with signed integers, unsigned integers, real types, and bit string types are supported.

Numeric to String

Conversions from numeric types to string representation.

Function

Description

Supported

SINT_TO_STRING

8-bit signed to string

Supported

INT_TO_STRING

16-bit signed to string

Supported

DINT_TO_STRING

32-bit signed to string

Supported

LINT_TO_STRING

64-bit signed to string

Not yet supported

USINT_TO_STRING

8-bit unsigned to string

Supported

UINT_TO_STRING

16-bit unsigned to string

Supported

UDINT_TO_STRING

32-bit unsigned to string

Supported

BYTE_TO_STRING

Byte to string

Supported

WORD_TO_STRING

Word to string

Supported

DWORD_TO_STRING

Double word to string

Supported

REAL_TO_STRING

Single-precision to string

Supported

LREAL_TO_STRING

Double-precision to string

Not yet supported

String to Numeric

Conversions from string representation to numeric types. The string must contain a valid numeric literal for the target type. What happens when it does not is implementer-specific in IEC 61131-3, so IronPLC selects it at compile time with two behavior policies; see String to Numeric Policies.

Function

Description

STRING_TO_SINT

String to 8-bit signed

STRING_TO_INT

String to 16-bit signed

STRING_TO_DINT

String to 32-bit signed

STRING_TO_LINT

String to 64-bit signed

STRING_TO_USINT

String to 8-bit unsigned

STRING_TO_UINT

String to 16-bit unsigned

STRING_TO_UDINT

String to 32-bit unsigned

STRING_TO_ULINT

String to 64-bit unsigned

STRING_TO_BYTE

String to byte

STRING_TO_WORD

String to word

STRING_TO_DWORD

String to double word

STRING_TO_LWORD

String to long word

STRING_TO_REAL

String to single-precision

STRING_TO_LREAL

String to double-precision

String to Numeric Policies

Real PLC platforms disagree about what STRING_TO_INT('12abc') returns, and IronPLC does not guess. Two behavior policies select the result at compile time. A dialect selects the alternatives its platform documents, and the --policy-* flags replace the dialect’s selection. The alternatives are encoded in the compiled program, so the same .iplc behaves the same on every runtime.

--policy-string-to-num-non-numeric

What counts as convertible when the string has characters that are not part of a numeric literal.

reject (default)

The whole string, less surrounding whitespace, must be one literal. '12abc' is a failure. The strict choice, also what RuSTy does.

ignore-trailing

The literal at the start of the string is converted and the rest is ignored. '12abc' converts to 12; 'abc12' is a failure. CODESYS and TwinCAT stop at the first invalid character.

ignore-surrounding

Characters that cannot start a literal are skipped, then the literal is converted and the rest is ignored. 'abc12' and 'x=12;' both convert to 12. Rockwell Logix STOD skips leading non-numeric characters this way.

--policy-string-to-num-failure

What happens when the string is not convertible: not a literal under the selected non-numeric policy, or a literal whose value does not fit the target type. A value out of range is a failure under every non-numeric alternative; nothing wraps.

trap (default)

The program halts with runtime error V4006, which names the offending string.

zero

The conversion produces zero and the program continues. CODESYS, TwinCAT and RuSTy return 0.

Under every alternative the accepted literal is the IEC 61131-3 literal of the target type. For an integer target that is decimal digits with optional _ separators ('1_000'), or a based literal ('16#FF', '8#17', '2#1010'), optionally signed. For a real target it is a floating-point number, also in exponential notation: digits with an optional decimal point and fraction ('9.876', '5', '.5') and an optional exponent ('1.2E-34'), optionally signed. A typed prefix ('UDINT#5') is not accepted, and neither are the words inf and nan. A decimal point is not part of an integer literal: STRING_TO_INT('12.5') is a failure under reject and 12 under ignore-trailing, which is what CODESYS documents.

Results of STRING_TO_UDINT by policy

Input

reject + trap

reject + zero

ignore-trailing + zero

ignore-surrounding + zero

'4294967295'

4294967295

4294967295

4294967295

4294967295

'16#FF'

255

255

255

255

'12abc'

V4006

0

12

12

'abc12'

V4006

0

0

12

'4294967296'

V4006

0

0

0

The dialects select the following alternatives:

Dialect

Non-numeric

Failure

iec61131-3-ed2, iec61131-3-ed3

reject

trap

rusty

reject

zero

codesys, twincat

ignore-trailing

zero

For a literal that does not fit the target type, the CODESYS documentation says the result depends on the processor. IronPLC does not emulate an undefined result: under the codesys and twincat dialects the failure policy applies and the result is zero. That is IronPLC’s choice, not a CODESYS behavior.

A literal outside the target’s range is a failure under every non-numeric alternative, never a wrap: STRING_TO_SINT('300') halts with V4006 or produces zero, and is never 44. The ranges are those of the types:

Function

Smallest

Largest

STRING_TO_SINT

-128

127

STRING_TO_INT

-32768

32767

STRING_TO_DINT

-2147483648

2147483647

STRING_TO_LINT

-9223372036854775808

9223372036854775807

STRING_TO_USINT, STRING_TO_BYTE

0

255

STRING_TO_UINT, STRING_TO_WORD

0

65535

STRING_TO_UDINT, STRING_TO_DWORD

0

4294967295

STRING_TO_ULINT, STRING_TO_LWORD

0

18446744073709551615

Results of STRING_TO_SINT by policy

Input

reject + trap

reject + zero

ignore-trailing + zero

ignore-surrounding + zero

'-128'

-128

-128

-128

-128

'300'

V4006

0

0

0

'-5abc'

V4006

0

-5

-5

STRING_TO_BYTE, STRING_TO_WORD, STRING_TO_DWORD and STRING_TO_LWORD convert exactly as STRING_TO_USINT, STRING_TO_UINT, STRING_TO_UDINT and STRING_TO_ULINT do, and compile to the same instruction, so a V4006 from one of them names the unsigned integer type of the same width.

For a real target, a literal whose magnitude rounds to infinity at the target’s precision ('1e39' for REAL, '1e309' for LREAL) does not fit the target and is a failure, exactly as '300' does not fit SINT. A literal too small for the precision rounds to zero or to a subnormal and is not a failure. No conversion produces a NaN or an infinity: under zero a failure produces positive 0.0.

Results of STRING_TO_REAL by policy

Input

reject + trap

reject + zero

ignore-trailing + zero

ignore-surrounding + zero

'1.2E-34'

1.2E-34

1.2E-34

1.2E-34

1.2E-34

'1.5abc'

V4006

0.0

1.5

1.5

'x=.5;'

V4006

0.0

0.0

0.5

'1e39'

V4006

0.0

0.0

0.0

'NaN'

V4006

0.0

0.0

0.0

PROGRAM main
VAR
    text : STRING := '4294967295';
    value : UDINT;
END_VAR
value := STRING_TO_UDINT(text);  (* value = 4294967295 *)
END_PROGRAM

Description

Type conversion functions explicitly convert values from one data type to another. IEC 61131-3 does not perform implicit type conversions; all conversions must use the appropriate *_TO_* function.

When a conversion may lose data (narrowing conversions), the behavior depends on the implementation. Values that exceed the range of the target type may be truncated or cause a runtime error.

Example

int_val := REAL_TO_INT(REAL#3.14);     (* int_val = 3 *)
real_val := INT_TO_REAL(42);            (* real_val = 42.0 *)
big_val := INT_TO_DINT(1000);           (* big_val = 1000, widening *)

See Also

References