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.