Comparing CHAR Arrays in STEP 7 V5.6: SCL and STL Methods

David Krause15 min read
S7-300SiemensTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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.

STEP 7 V5.6 ships with SCL as an optional installation component. If SCL is not licensed or installed on the programming station, only STL and LAD/FBD are available. Confirm S7-SCL is present in the SIMATIC Manager under Options > Add-on Packages before attempting the SCL methods below.

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.

A common field mistake is to compare an 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: TRUE when all 32 bytes match, FALSE otherwise. 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 of EQ_STRNG.
  • If all 32 bytes match, firstDiffIx remains 0. Use 0 as the "all equal" sentinel.
  • FC20 (the function return value) is set to equalFlag. 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 i is declared INT. The SCL runtime increments i by 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

  • WHILE re-evaluates the condition on every iteration. The combined (i <= iLength) AND (FC30 = TRUE) short-circuits both at length and at first mismatch.
  • The index i must be incremented manually. Forgetting the i := i + 1 line 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 WHILE when 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 favors WHILE patterns for this reason).
The 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##aData with LAR1 so the code survives renumbering. The previous-generation SLD 3 / LAR1 / +AR1 pattern 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 to P#2.0 and 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 LOOP instruction decrements the accumulator (loaded with iCnt) 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:

  1. The variable was declared VAR_TEMP in the source but the editor stripped the # prefix during paste. Re-add the # before every read/write.
  2. The variable name uses a reserved SCL keyword (for example, RESULT). Rename to resultFlag or similar.
  3. 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.

Inside an SCL source file in STEP 7 V5.6 the # 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:

  1. Function return value (preferred): set the function name on the last line. Compact, idiomatic, and the call site can use the result inline.
  2. 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.
  3. 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

  1. Compile the SCL source. Confirm zero warnings on the "Compile" tab of the SCL editor.
  2. 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.
  3. Open a VAT (Variable Table) and force both aData and bData to identical values. Confirm the function returns TRUE.
  4. Flip a single byte (for example, aData[5]). Confirm the function returns FALSE and firstDiffIx equals 5.
  5. Watch iCnt in the STL version to confirm the loop runs the expected 16 or 32 iterations.
  6. 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.

Back to blog