P4049

Code

P4049

Message

Operator is not defined for the operand types

This error occurs when an operator is applied to operand types it is not defined for. The message names the operator and the operand types.

The arithmetic operators +, -, * and / are defined for two numeric operands (SINT through ULINT, REAL and LREAL) where one widens to the other, and for the time and date combinations listed on the ADD, SUB, MUL and DIV pages, such as a TIME plus a TIME or a DATE minus a DATE. MOD is defined for two integer operands only. The function forms ADD, SUB, MUL and DIV are checked the same way and report this error too, naming the two operand types of the step that fails; MOD(a, b) is checked against its signature and reports P4026 instead.

Each arithmetic expression is reported once, naming both operand types. When an operand of an expression is itself an expression that failed, the enclosing expression may be reported as well.

Mixed numeric types

The following code will generate error P4049:

PROGRAM main
VAR
    count : DINT := 7;
    factor : REAL := 1.5;
    scaled : REAL;
END_VAR
    scaled := factor * count;
END_PROGRAM

A DINT does not widen to REAL without loss, because REAL cannot hold every 32-bit integer exactly, and a REAL does not widen to DINT. Neither operand can take the other’s type, so the operator is not defined for the pair. The same applies to a signed and an unsigned integer of the same width, such as DINT and UDINT.

To fix this error, convert one operand explicitly, or use a type that holds both:

PROGRAM main
VAR
    count : DINT := 7;
    factor : REAL := 1.5;
    scaled : REAL;
END_VAR
    scaled := factor * DINT_TO_REAL(count);   (* 10.5 *)
END_PROGRAM

See Type Conversions for which types widen to which.

Time and date operands

The following code will generate error P4049:

PROGRAM main
VAR
    interval : TIME := T#2s;
    repeats : TIME := T#3s;
    total : TIME;
END_VAR
    total := interval * repeats;
END_PROGRAM

A duration can be multiplied or divided by a number, but not by another duration, and two dates can be subtracted but not added.

To fix this error, use a number for the factor:

PROGRAM main
VAR
    interval : TIME := T#2s;
    repeats : DINT := 3;
    total : TIME;
END_VAR
    total := interval * repeats;   (* T#6s *)
END_PROGRAM

Remainder of a real number

The following code will generate error P4049:

PROGRAM main
VAR
    angle : REAL := 400.5;
    wrapped : REAL;
END_VAR
    wrapped := angle MOD 360.0;
END_PROGRAM

MOD accepts only integer operands. There is no floating-point remainder operator.

To fix this error, convert the operands to an integer type when an integer remainder is what you want:

PROGRAM main
VAR
    angle : REAL := 400.5;
    wrapped : DINT;
END_VAR
    wrapped := REAL_TO_DINT(angle) MOD 360;
END_PROGRAM

For a floating-point remainder, subtract the truncated quotient. TRUNC drops the fractional part of the quotient, and the <INT>_TO_<REAL> conversion brings it back to the operand type:

PROGRAM main
VAR
    angle : REAL := 400.5;
    wrapped : REAL;
END_VAR
    wrapped := angle - DINT_TO_REAL(TRUNC(angle / 360.0)) * 360.0;  (* 40.5 *)
END_PROGRAM

The result has the sign of the dividend, as MOD does for integers.

Arithmetic on bit strings

The following code will generate error P4049 unless bit-string arithmetic is enabled:

PROGRAM main
VAR
    counter : BYTE;
END_VAR
    counter := counter + 1;
END_PROGRAM

IEC 61131-3 defines no arithmetic on the bit-string types. CODESYS, TwinCAT and RuSTy treat a bit string as the unsigned integer of its width, and IronPLC does the same with --allow-bit-string-arithmetic. See Enabling Dialects and Features for how to enable it.

Without the flag, declare the variable as an unsigned integer of the same width:

PROGRAM main
VAR
    counter : USINT;
END_VAR
    counter := counter + 1;
END_PROGRAM

Bit-string operators

The bit-string operators AND, OR, XOR and NOT are defined over the bit-string types (BOOL, BYTE, WORD, DWORD, LWORD). For these operators, each operand outside that set is reported separately, naming the expected category and the actual type.

The following code will generate error P4049:

PROGRAM main
VAR
    flags : DINT := 10;
    masked : DINT;
END_VAR
    masked := flags AND 3;
END_PROGRAM

The variable flags is a DINT, but AND accepts only bit-string operands. x AND 3 where x is a DINT does not mean a bitwise AND of the two numbers.

To fix this error, declare the operands as a bit-string type of the width you want:

PROGRAM main
VAR
    flags : BYTE := 16#0A;
    masked : BYTE;
END_VAR
    masked := flags AND BYTE#16#03;   (* 16#02 *)
END_PROGRAM

The same applies to NOT, whose operand is a single bit string:

PROGRAM main
VAR
    flags : BYTE := 16#0F;
    inverted : BYTE;
END_VAR
    inverted := NOT flags;   (* 16#F0 *)
END_PROGRAM

Think IronPLC is wrong about this?

If you believe this diagnostic is incorrect, open an issue on GitHub with a small sample that demonstrates the problem.