1. Overview: Comparing CHAR Arrays in STEP 7 V5.6
Comparing two arrays of CHAR (8-bit characters) in SIMATIC STEP 7 V5.6 requires explicit logic because the standard FC10 EQ_STRNG instruction only operates on the STRING data type, which is a 2-byte length header followed by up to 254 characters. When the source data is a fixed-length array of 32 bytes organized as ARRAY[1..32] OF CHAR, you must implement the comparison either through the SCL (Structured Control Language) compiler's built-in array comparison, a manual loop, or through STL with indirect addressing.
This reference covers the three production-ready methods, plus the block interface declarations and result output patterns that engineers typically need when porting a comparison routine from TIA Portal back to STEP 7 V5.6. The example uses a 32-byte payload, but the patterns apply to any fixed-length CHAR or BYTE array from 1 to 65535 elements.
2. Data Type Considerations: CHAR vs STRING vs BYTE
Before writing the comparison, identify exactly what the array represents. The four candidates engineers typically confuse are CHAR, STRING, BYTE, and ARRAY OF CHAR:
| Data type | Width | Range | Typical use | IEC standard |
|---|---|---|---|---|
| CHAR | 8 bits | ASCII 0..255 (signed -128..+127) | Single printable character | Yes |
| STRING | 2 + n bytes | Up to 254 characters + admin bytes | Variable-length ASCII string with length header | Yes |
| BYTE | 8 bits | 0..255 unsigned | Raw binary buffer | Yes |
| ARRAY OF CHAR | n bytes | Fixed-length, no header | Structured payload, protocol frames | Yes |
Two arrays are only directly comparable with the = operator in SCL when their structures are identical: same element type, same lower bound, same upper bound, and same length. If the data is actually a STRING and you only need a length-bounded prefix comparison, EQ_STRNG (FC10 from the Standard Library > IEC Function Blocks) is more efficient because the runtime can short-circuit at the first differing character using the STRING's internal length field.
ARRAY[0..31] OF CHAR against an ARRAY[1..32] OF CHAR. The SCL compiler will flag this as a type error because the lower index does not match. Standardize on either 0-based or 1-based indexing across both arrays before compiling.3. Method 1: Direct Array Comparison in SCL
The SCL compiler in STEP 7 V5.6 supports a built-in element-wise comparison of two arrays with identical structure. No loop is required — the compiler emits an MC7 sequence that walks both arrays and reports the first mismatch as FALSE. This is the shortest possible code and is the recommended approach when the two arrays are guaranteed to share structure.
FC10 — Direct array equality
FUNCTION FC10 : BOOL
VAR_INPUT
aData : ARRAY[1..32] OF CHAR;
bData : ARRAY[1..32] OF CHAR;
END_VAR
BEGIN
FC10 := (aData = bData);
END_FUNCTION
The SCL compiler lowers aData = bData into a sequence of byte loads and a single branch on first mismatch. Execution time is O(n) and is comparable to a hand-written loop.
Restrictions
- Both arrays must be declared with the same lower bound, upper bound, and element type.
- Array elements cannot include STRING, WSTRING, STRUCT, or ARRAY subtypes in a single
=expression — the SCL compiler rejects nested non-elementary types. The SCL manual documents the elementary type list for direct comparison. - The result is returned as BOOL:
TRUEwhen all 32 bytes match,FALSEotherwise. The function does not return the index of the first mismatch — use Method 2 for that.
Reference: S7-SCL V5.6 Programming Manual (Siemens Support entry 109751142)
4. Method 2: FOR Loop Element-by-Element in SCL
When the engineer needs the index of the first mismatch (for diagnostics, logging, or selective branch handling) the SCL FOR loop is the right tool. The following FC returns both the boolean equality flag and the position of the first differing byte.
FC20 — Compare with mismatch index
FUNCTION FC20 : BOOL
VAR_INPUT
aData : ARRAY[1..32] OF CHAR;
bData : ARRAY[1..32] OF CHAR;
END_VAR
VAR_OUTPUT
equalFlag : BOOL;
firstDiffIx : INT;
END_VAR
VAR
i : INT;
END_VAR
BEGIN
equalFlag := TRUE;
firstDiffIx := 0;
FOR i := 1 TO 32 DO
IF aData[i] <> bData[i] THEN
equalFlag := FALSE;
firstDiffIx := i;
EXIT;
END_IF;
END_FOR;
FC20 := equalFlag;
END_FUNCTION
Behavior
-
EXIT;terminates the loop on the first mismatch, mirroring the short-circuit semantics ofEQ_STRNG. - If all 32 bytes match,
firstDiffIxremains0. Use 0 as the "all equal" sentinel. -
FC20(the function return value) is set toequalFlag. This double-output pattern is useful because the call site can use the return value for inline branching and the output for HMI display. - Index variable
iis declaredINT. The SCL runtime incrementsiby 1 each iteration; no manual increment is required.
Why use EXIT instead of GOTO? The SCL manual discourages GOTO jumps in structured code. EXIT; is the documented early-exit statement and is supported by all SCL versions bundled with STEP 7 V5.4 through V5.6.
Reference: S7-SCL V5.6 Programming Manual — Control Structures (Section 4)
5. Method 3: WHILE Loop with Early Exit in SCL
A WHILE loop is preferred when the array length is not known at compile time (for example, when the length is passed in as a parameter) or when the loop must abort as soon as a mismatch is detected. The semantics are identical to the FOR version, but the condition is evaluated before each iteration, allowing zero-length arrays to be handled without a special case.
FC30 — Length-parameterized comparison
FUNCTION FC30 : BOOL
VAR_INPUT
aData : ARRAY[1..32] OF CHAR;
bData : ARRAY[1..32] OF CHAR;
iLength : INT;
END_VAR
VAR_OUTPUT
firstDiffIx : INT;
END_VAR
VAR
i : INT;
END_VAR
BEGIN
FC30 := TRUE;
firstDiffIx := 0;
i := 1;
WHILE (i <= iLength) AND (FC30 = TRUE) DO
IF aData[i] <> bData[i] THEN
FC30 := FALSE;
firstDiffIx := i;
END_IF;
i := i + 1;
END_WHILE;
END_FUNCTION
Key differences from the FOR loop
-
WHILEre-evaluates the condition on every iteration. The combined(i <= iLength) AND (FC30 = TRUE)short-circuits both at length and at first mismatch. - The index
imust be incremented manually. Forgetting thei := i + 1line produces an infinite scan-time overrun — a common field bug. The CPU will stop on OB121 / OB122 and the diagnostic buffer will show "cycle time overflow." - Use
WHILEwhen the array is passed as a parameter with a flexible length, when comparing a partial prefix, or when implementing a SCL function that needs to be callable from a TIA Portal library (TIA Portal's SCL favorsWHILEpatterns for this reason).
WHILE version generates roughly the same MC7 code as the FOR version on the S7-300/400 compiler. The choice is therefore about readability and parameterized length support, not performance. For a CPU 315-2 PN/DP, both versions of a 32-byte comparison execute in < 50 µs of OB1 time.6. Method 4: STL with Indirect Addressing
If SCL is not installed or the engineer must stay in pure STL (for example, on a legacy S7-300 with a 318-2 CPU that only ships with the older SCL V5.3), use the LOOP instruction in combination with two area pointers and indirect byte addressing. This is the most verbose option but it works on every STEP 7 V5.x install without an additional license.
FC40 — STL byte-by-byte comparison
FUNCTION FC40 : BOOL
VAR_INPUT
aData : ARRAY[1..32] OF CHAR;
bData : ARRAY[1..32] OF CHAR;
END_VAR
VAR_TEMP
pA : POINTER;
pB : POINTER;
iCnt : INT;
iIx : INT;
equal : BOOL;
END_VAR
BEGIN
NETWORK 1
TITLE = Initialize pointers and counter
LAR1 P##aData; // AR1 -> aData
LAR2 P##bData; // AR2 -> bData
L 16; // 32 bytes / 2 = 16 word compares
T #iCnt;
L 1;
T #iIx;
SET;
= #equal;
NETWORK 2
TITLE = Compare loop (2 bytes per iteration)
LOOP: L DBW [AR1,P#0.0]; // Load word from aData
L DBW [AR2,P#0.0]; // Load word from bData
<>I ;
JC NOTEQ; // Branch on first mismatch
+AR1 P#2.0; // Advance AR1 by 2 bytes
+AR2 P#2.0; // Advance AR2 by 2 bytes
L #iIx;
+ 2;
T #iIx; // Track firstDiffIx position
L #iCnt;
LOOP LOOP; // Decrement and loop
JU DONE;
NOTEQ: CLR;
= #equal;
L #iIx;
T ... // FirstDiffIx output
DONE: NOP 0;
FC40 := #equal;
END_FUNCTION
Notes on the STL version
- Use the symbolic pointer
P##aDatawithLAR1so the code survives renumbering. The previous-generationSLD 3 / LAR1 / +AR1pattern is not portable across STEP 7 versions and is not recommended. - Compare two bytes at a time (word load) to halve the number of loops and to use the
<>I(16-bit integer inequality) instruction directly. Adjust the pointer increment toP#2.0and the loop count to 16 for a 32-byte array. - Capture the position of the first mismatch by maintaining a parallel index counter; the snippet above shows the pattern. The pointer is advanced after the comparison so the captured index always points at the failing byte.
- The
LOOPinstruction decrements the accumulator (loaded withiCnt) and jumps back if the result is non-zero. The accumulator must be loaded with the initial loop count before the loop body.
Reference: S7-SCL and STL Reference Manual (Siemens Support entry 109751142)
7. Declaring CHAR Array Inputs on FC/FB Blocks
A frequent error when porting TIA Portal blocks back to STEP 7 V5.6 is the IN/OUT/TEMP declaration of an array. The following table summarizes the declaration rules for a 32-byte CHAR array on an FC and an FB.
| Block type | Declaration section | Allowed form | Notes |
|---|---|---|---|
| FC | VAR_INPUT | ARRAY[1..32] OF CHAR | Passed by value; pointer generated in the local TEMP section |
| FC | VAR_IN_OUT | ARRAY[1..32] OF CHAR | Passed by reference (pointer only); allows the FC to modify the source |
| FB | VAR_INPUT, VAR_IN_OUT, VAR (stat) | ARRAY[1..32] OF CHAR | All three are allowed; STAT retains values between calls |
| FB multi-instance | VAR (stat) | ARRAY[1..32] OF CHAR | Each instance gets its own copy in the parent's DI |
For a comparison routine that does not modify either source array, declare both as VAR_INPUT. The SCL compiler will generate a temporary pointer to the caller's data block and load the bytes indirectly. The runtime cost of VAR_INPUT versus VAR_IN_OUT is negligible for a 32-byte array.
For SCL source that originated in TIA Portal, watch for the ARRAY[*] upper-bound syntax (TIA V15+). STEP 7 V5.6 does not support *; convert to a fixed upper bound before compiling, otherwise the SCL compiler raises SF0201 "Type declaration incorrect."
8. The "#" Prefix and Local Variable Scope
The # prefix is the STEP 7 V5.x convention for accessing local variables (TEMP, STAT, INPUT, OUTPUT, IN_OUT) inside an FB, FC, or multi-instance block. In TIA Portal the same prefix is allowed but is optional; in STEP 7 V5.6 the prefix is also optional in SCL, but required in STL and LAD/FBD.
A common compile error after copying TIA SCL code into STEP 7 V5.6 is SF0204 "Identifier not declared", which is almost always caused by one of three things:
- The variable was declared
VAR_TEMPin the source but the editor stripped the#prefix during paste. Re-add the#before every read/write. - The variable name uses a reserved SCL keyword (for example,
RESULT). Rename toresultFlagor similar. - The variable is declared inside a nested block (such as a CASE branch) and is therefore not visible in the outer scope.
The original STEP 7 V5.4 compiler was stricter about the # prefix than V5.6. Code that compiled in V5.4 may compile in V5.6 without changes, but the opposite is not always true. When the FC was first written in V5.4, the index variable was written with #i; the engineer stripped the # when moving to V5.6, which immediately resolved the compile error and confirmed that the original "identifier not declared" complaint was a prefix mismatch.
# is optional for VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, and VAR declarations. The prefix is still useful for readability and to disambiguate a local name from a global DB symbol of the same name.9. Result Output and Block Interface Design
The function return value of an SCL FC is the primary way to return a BOOL result. The most common call-site error after porting from TIA Portal is forgetting to assign the return value to the function name itself. The SCL rule is: the function return value is assigned to the function name on the last line of the function body.
FUNCTION CompareArrays : BOOL
VAR_INPUT
aData : ARRAY[1..32] OF CHAR;
bData : ARRAY[1..32] OF CHAR;
END_VAR
BEGIN
// ... comparison logic ...
CompareArrays := equalFlag; // Final assignment to function name
END_FUNCTION
If the engineer instead writes equalFlag := FALSE; on the last line and forgets to assign to CompareArrays, the function returns the default initial value of BOOL (FALSE), and the call site always sees "not equal." This is the exact symptom described in the original troubleshooting chain: the engineer had to delete the last erroneous code line and explicitly write the result out of the FC.
For BOOL results that must be visible in the HMI or a function block call, use one of three patterns:
- Function return value (preferred): set the function name on the last line. Compact, idiomatic, and the call site can use the result inline.
- VAR_OUTPUT equalFlag: set an output parameter explicitly. Use when the result must be wired to a DB tag, an HMI tag, or a PII/PQO bit.
- VAR_IN_OUT equalFlag: only when the caller passes a tag by reference and expects the FC to overwrite it. Rarely needed for a comparison routine.
For ARRAY inputs on a FB multi-instance, declare the array as VAR (stat) in the parent block so each child instance gets its own copy. Memory cost is 32 bytes per child instance, plus 2 bytes of pointer overhead in the parent's DI. For a parent FB with 8 child comparison instances, this is 256 + 16 = 272 bytes of static RAM.
10. Verification, Commissioning, and Troubleshooting Matrix
After compiling, follow this matrix to commission and verify the comparison FC in OB1 or a cyclic OB.
| Symptom | Likely cause | Diagnostic | Fix |
|---|---|---|---|
| Compile error SF0204 "Identifier not declared" | Missing # prefix in SCL or undeclared local |
Open the SCL source, search for the variable name | Add # or move the declaration to VAR_INPUT/OUT |
| Compile error SF0201 "Type declaration incorrect" | Lower bound or upper bound mismatch between arrays | Compare both ARRAY[..] declarations |
Align lower and upper bounds to 1..32 (or 0..31) |
| FC always returns FALSE | Forgotten CompareArrays := equalFlag; on last line |
Open the compiled STL and check the BR/ENO bit | Add the assignment to the function name on the last line |
| Scan time overrun in OB1 | WHILE loop with no i := i + 1
|
Check the loop index variable in VAT | Add the increment line and recompile |
| Result is correct for <5 bytes, wrong for full 32 | Array length parameter passed as constant 5 instead of 32 | Check the iLength input in the VAT |
Update the call site to pass 32 |
| Index out of range (OB121 stop) | Loop counter exceeds array upper bound | Look at the buffer pointer in the diagnostic buffer | Clamp the loop to 1..32 with FOR
|
| EQ_STRNG returns "equal" for unequal CHAR arrays | Source data is a STRING, not a CHAR array; FC10 misapplied | Cross-check the data block declaration | Switch to a CHAR-based comparison FC (this article) |
Verification procedure
- Compile the SCL source. Confirm zero warnings on the "Compile" tab of the SCL editor.
- Download the FC into the AS. The SCL compiler writes the MC7 code into the offline block; STEP 7 will prompt to download the entire program if the FC's interface signature changed.
- Open a VAT (Variable Table) and force both
aDataandbDatato identical values. Confirm the function returnsTRUE. - Flip a single byte (for example,
aData[5]). Confirm the function returnsFALSEandfirstDiffIxequals 5. - Watch
iCntin the STL version to confirm the loop runs the expected 16 or 32 iterations. - Trigger OB1 with a temporary
SINGLE SCAN(PLCSIM) and inspect the SZL partial list for scan time delta.
For a final acceptance test, run the FC in OB35 (cyclic interrupt) at 100 ms and log the result to a watch table over a 1-hour soak test. Any single-bit corruption in the source data will be caught by the comparison and logged with the firstDiffIx for diagnostics.
11. Frequently Asked Questions
Can I use FC10 EQ_STRNG to compare two CHAR arrays?
No. EQ_STRNG (FC10) operates on the STRING data type, which has a 2-byte length header followed by up to 254 characters. A CHAR array is a fixed-length sequence without the header. Use one of the SCL or STL methods in this article for CHAR array comparison.
Which SCL loop is faster for a 32-byte array, FOR or WHILE?
Performance is identical on the S7-300/400 compiler. Both generate the same MC7 instruction sequence. Choose FOR for fixed-length arrays and WHILE for parameterized lengths or partial-prefix comparison.
Why does my FC always return FALSE in STEP 7 V5.6 but works in TIA Portal?
The most common cause is that the function name is not assigned on the last line of the function body. SCL in STEP 7 V5.6 (and TIA Portal) requires the return value to be assigned to the function name explicitly. Add CompareArrays := equalFlag; as the final statement.
How do I declare a 32-byte CHAR array input on an FC?
Use VAR_INPUT aData : ARRAY[1..32] OF CHAR;. For pass-by-reference, use VAR_IN_OUT. Both arrays must share the same lower bound, upper bound, and element type, or the SCL compiler raises SF0201.
Do I need SCL installed to compare CHAR arrays in STEP 7 V5.6?
Yes for the SCL methods. If SCL is not available, use the STL approach with LAR1/LAR2 and the LOOP instruction as shown in section 6. STL works on every STEP 7 V5.x install without an additional license.