P4049

Code

P4049

Message

Operator is not defined for the operand type

This error occurs when an operator is applied to an operand whose type the operator is not defined for.

IEC 61131-3 defines the MOD operator only for the integer types (SINT, INT, DINT, LINT, USINT, UINT, UDINT, ULINT). There is no floating-point remainder operator, so a REAL or LREAL operand is a type error.

The bit-string operators AND, OR, XOR and NOT are defined over the bit-string types (BOOL, BYTE, WORD, DWORD, LWORD). An integer operand is a type error: x AND 3 where x is a DINT does not mean a bitwise AND of the two numbers. Convert the operand to a bit-string type of the same width when a bit-wise result is what you want.

The function form of an operator accepts the same operand types as the operator itself. A mismatch there is reported as P4026 instead.

Example

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

The variable angle is REAL, but MOD accepts only integer operands.

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.

Bit-string operators

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.

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 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.