Wie kann der Ergebniswert bei verschachtelten String-Bausteinen vollständig abgebildet werden?

Falls Sie Bausteine mit STRING-Werten ohne einer maximalen Länge (z.B. String-Bausteine) verschachtelt in der Anwendung verwenden, ist der zur Verfügung stehende Speicher dafür beschränkt. Diese Beschränkung ist abhängig vom verwendeten Zielsystem (siehe "Zielsystem-spezifische Eigenschaften und Einschränkungen"). In Folge ist es möglich, dass:

  • ein Ergebniswert nicht vollständig im zur Verfügung stehenden Speicher abgebildet werden kann

und

  • bei einem anderen Zielsystem ein unterschiedlich langer Ergebniswert entsteht.

Falls Sie beide Folgen vermeiden wollen, verwenden Sie Bausteine mit STRING-Werten ohne einer maximalen Länge nicht verschachtelt. Bei anwenderdefinierten Bausteinen können beide erwähnten Folgen nicht eintreten, da darin die STRING-Variablen mit einer maximalen Länge deklariert werden müssen.
images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg Auch falls Sie die Bausteine nicht verschachtelt verwenden, ist es natürlich trotzdem möglich, dass der STRING-Ergebniswert nicht im zur Verfügung stehenden Speicher abgebildet werden kann. In diesem Fall wird übrigens der Ausgang ENO des Bausteins auf den Wert FALSE (oder eine Entsprechung) gesetzt (siehe auch Abschnitt "Interne Fehlerdiagnose für Baustein" in den Baustein-Beschreibungen, wie sich der Baustein verhält).

Die folgenden Beispiele mit dem CONCAT-Baustein geben Ihnen ein Überblick über mögliche Verwendungen und deren Folgen. Der CONCAT-Baustein wurde für die Beispiele ausgewählt, da er sowohl über Eingänge als auch über einen Ergebniswert vom Datentyp STRING ohne einer maximalen Länge verfügt. Die berechneten Werte werden mit Hilfe des Assert-Bausteins ausgewertet.

Beachten Sie: Je größer ein STRING-Wert ist, desto mehr Arbeitsspeicher wird am Zielsystem benötigt. Falls kein ausreichender Arbeitsspeicher auf dem Zielsystem verfügbar ist, kann die Anwendung auf das Zielsystem wahrscheinlich gar nicht erfolgreich geladen werden.

Beispiel 1: CONCAT ohne Verschachtelung, ENO=TRUE

Der Ergebniswert wird vollständig abgebildet, da resultString1 mit einer Länge von 300 Zeichen deklariert ist. Das Verhalten auf unterschiedlichen Zielsystemen ist identisch, da CONCAT nicht verschachtelt benutzt wird (die Beschränkung des Speichers wird hier nicht angewendet).

FUNCTION_BLOCK ConcatSample1
VAR
resultString1 : STRING[300];
length1 : INT;
eno1 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* The 3 inputs amount to 300 characters. This is OK because 'resultString1' has a length of 300 characters. So 'eno1' evaluates to 'TRUE'. *)
resultString1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>eno1);
length1 := LEN(resultString1);
ASSERT(length1=300);
ASSERT(eno1);
END_FUNCTION_BLOCK

Beispiel 2: CONCAT ohne Verschachtelung, ENO=FALSE (da Ergebniswert zu lang)

Der Ergebniswert wird nicht vollständig abgebildet, da resultString2 mit einer Länge von 200 Zeichen deklariert ist. Das Verhalten auf unterschiedlichen Zielsystemen ist aber identisch, da CONCAT nicht verschachtelt benutzt wird (die Beschränkung des Speichers wird hier nicht angewendet).

FUNCTION_BLOCK ConcatSample2
VAR
resultString2 : STRING[200];
length2 : INT;
eno2 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* The 3 inputs amount to 300 characters. But 'resultString2' has a length of 200 characters. So 'eno2' evaluates to 'FALSE'. *)
resultString2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>eno2);
length2 := LEN(resultString2);
ASSERT(length2=200);
ASSERT(NOT eno2);
END_FUNCTION_BLOCK

Beispiel 3: CONCAT ohne Verschachtelung, ENO=TRUE – keine Beschränkung auf 1.024 Zeichen

Der Ergebniswert wird vollständig abgebildet, da resultString3 mit einer Länge von 1.500 Zeichen deklariert ist. Das Verhalten auf unterschiedlichen Zielsystemen ist identisch, da CONCAT nicht verschachtelt benutzt wird. Auch hier wird die Beschränkung des Speichers nicht angewendet. Dies ist daran erkennbar, dass der Ergebniswert von 1.100 Zeichen vollständig abgebildet wird (eigentlich würde er die Grenze von 1.024 Bytes beim Laufzeitsystem für Windows überschreiten).

FUNCTION_BLOCK ConcatSample3
VAR
resultString3 : STRING[1500];
length3 : INT;
eno3 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* The 11 inputs amount to 1100 characters. This is OK again because 'resultString3' has a length of 1500 characters. So 'eno3' evaluates to 'TRUE'. *)
resultString3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, IN4 := stringLength100, IN5 := stringLength100, IN6 := stringLength100, IN7 := stringLength100, IN8 := stringLength100, IN9 := stringLength100, IN10 := stringLength100, IN11 := stringLength100, ENO=>eno3);
length3 := LEN(resultString3);
ASSERT(length3=1100);
ASSERT(eno3);
END_FUNCTION_BLOCK

Beispiel 4: CONCAT mit Verschachtelung, ENO einiger inneren CONCATs=FALSE – Beschränkung auf 1.024 Zeichen

Der zusammengesetzte Ergebniswert wird nicht vollständig abgebildet, obwohl resultString4 mit einer Länge von 1.500 Zeichen deklariert ist. Das Verhalten auf unterschiedlichen Zielsystemen ist nicht identisch, da CONCAT verschachtelt benutzt wird. Somit wird hier die Beschränkung des Speichers angewendet – beim Laufzeitsystem für Windows ist dies 1.024 Bytes, wobei 1 Byte von diesem Speicher pro CONCAT-Aufruf außerdem für interne Zwecke verwendet wird. Falls eine andere Beschränkung für das Zielsystem gilt (z.B. für Controllinos), entsteht ein anderer Ergebniswert.

FUNCTION_BLOCK ConcatSample4
VAR
resultString4a : STRING[1500];
length4a : INT;
eno4a, enoA1, enoB1, enoC1, enoD1 : BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* Here there is a nested usage of CONCAT. The scenario is as follows:
Unsized strings are assigned to 4 inputs of the outer CONCAT by calling CONCAT blocks again. Let's call them the inner CONCATs.
A string with a length of 100 characters is assigned to the 3 inputs of each inner CONCAT. For runtime system for Windows, this is valid:
* The 3 inputs of the 1st inner CONCAT amount to 300 characters. 1 byte of the memory is used for internal purpose. As 301 < 1024, 'enoA1' evaluates to 'TRUE'. 300 characters can be mapped in the available memory.
* The 3 inputs of the 2nd inner CONCAT ampunt to 300 characters as well. 1 byte of the memory is again used for internal purpose. As 602 < 1024, 'enoB1' evaluates to 'TRUE'. 300 characters can be mapped in the available memory.
* The 3 inputs of the 3rd inner CONCAT amount to 300 characters as well. 1 byte of the memory is again used for internal purpose. As 903 < 1024, 'enoC1' evaluates to 'TRUE'. 300 characters can be mapped in the available memory.
* The 3 inputs of the 4th inner CONCAT amount to 300 characters as well. 1 byte of the memory is again used for internal purpose. As 1204 > 1024, 'enoD1' evaluates to 'FALSE'. Only 120 characters (of the 300 characters) can be mapped in the available memory.
So a string of 1020 characters is assigned to the outer CONCAT (300 + 300 + 300 + 120). This is OK because 'resultString4a' has a length of 1500 characters. So 'eno4a' evaluates to 'TRUE'. *)
resultString4a := CONCAT(IN1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoA1), IN2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoB1), IN3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoC1), IN4 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoD1), ENO=>eno4a);
length4a := LEN(resultString4a);
ASSERT(length4a=1020); (* Valid for: runtime system for Windows. In case of a Controllino Maxi Automation, 'resultString4a' would just have a length of 63 characters. *)
ASSERT(eno4a);
ASSERT(enoA1); (* Valid for: runtime system for Windows. In case of a Controllino Maxi Automation, 'enoA1' to 'enoD1' would evaluate to 'FALSE'. *)
ASSERT(enoB1);
ASSERT(enoC1);
ASSERT(NOT enoD1);
END_FUNCTION_BLOCK

Beispiel 5: Analog zu Beispiel 4, aber ohne Verschachtelung und alle ENO=TRUE – keine Beschränkung auf 1.024 Zeichen

Der Ergebniswert wird vollständig abgebildet, da resultString5 mit einer Länge von 3.000 Zeichen deklariert ist. Das Verhalten auf unterschiedlichen Zielsystemen ist identisch, da CONCAT nicht verschachtelt benutzt wird. Auch hier wird die Beschränkung des Speichers nicht angewendet. Dies ist daran erkennbar, dass der Ergebniswert von 1.200 Zeichen vollständig abgebildet wird (eigentlich würde er die Grenze von 1.024 Bytes beim Laufzeitsystem für Windows überschreiten).

FUNCTION_BLOCK ConcatSample5
VAR
resultString5 : STRING[1500];
length5 : INT;
eno5, enoV1, enoV2, enoV3, enoV4 : BOOL;
VarString1, VarString2, VarString3, VarString4 : STRING[300];
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* Here a workaround to avoid the restriction of 1024 bytes. Assign the result of the previously "inner" CONCAT blocks to STRING variables. Here all ENOs evaluate to 'TRUE'. *)
VarString1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV1);
VarString2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV2);
VarString3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV3);
VarString4 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoV4);
 
(* Then assign these STRING variables to the inputs of the previously "outer" CONCAT. This makes the code easier to read as well. *)
resultString5 := CONCAT(IN1 := VarString1, IN2 := VarString2, IN3 := VarString3, IN4 := VarString4, ENO=>eno5);
length5 := LEN(resultString5);
ASSERT(length5=1200);
ASSERT(eno5);
ASSERT(enoV1);
ASSERT(enoV2);
ASSERT(enoV3);
ASSERT(enoV4);
END_FUNCTION_BLOCK

Beispiel 6: Beispiel 4 um einen inneren CONCAT erweitert, ENO einiger inneren CONCATs=FALSE – Beschränkung auf 1.024 Zeichen

Der zusammengesetzte Ergebniswert wird wieder nicht vollständig abgebildet, obwohl resultString6 mit einer Länge von 1.500 Zeichen deklariert ist. Das Verhalten auf unterschiedlichen Zielsystemen ist nicht identisch, da CONCAT verschachtelt benutzt wird. Somit wird hier die Beschränkung des Speichers angewendet – bei Laufzeitsystem für Windows ist dies 1.024 Bytes, wobei 1 Byte von diesem Speicher pro CONCAT-Aufruf außerdem für interne Zwecke verwendet wird. Falls eine andere Beschränkung für das Zielsystem gilt (z.B. für Controllinos), entsteht ein anderer Ergebniswert.

FUNCTION_BLOCK ConcatSample6
VAR
resultString6 : STRING[1500];
length6 : INT;
eno6, enoA2, enoB2, enoC2, enoD2, enoE2: BOOL;
stringLength100 : STRING[100] := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
END_VAR
 
(* This is identical to example 4, but a 5th inner CONCAT is added. In addition to the behavior of example 4, the 300 characters of the 5th inner CONCAT cannot be mapped at all because there is no available memory left. So 'enoE2' evaluates to 'FALSE' (such as 'enoD2'). *)
resultString6 := CONCAT(IN1 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoA2), IN2 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoB2), IN3 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoC2), IN4 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoD2), IN5 := CONCAT(IN1 := stringLength100, IN2 := stringLength100, IN3 := stringLength100, ENO=>enoE2), ENO=>eno6);
length6 := LEN(resultString6);
ASSERT(length6=1020); (* Valid for: runtime system for Windows. In case of a Controllino Maxi Automation, 'resultString6' would just have a length of 63 characters. *)
ASSERT(eno6);
ASSERT(enoA2); (* Valid for: runtime system for Windows. In case of a Controllino Maxi Automation, 'enoA2' to 'enoD2' would evaluate to 'FALSE'. *)
ASSERT(enoB2);
ASSERT(enoC2);
ASSERT(NOT enoD2);
ASSERT(NOT enoE2);
END_FUNCTION_BLOCK