English
🠦 Deutsch
The Nexeed string function OpconStrCat() for string concatenation must not be called with SIZEOF(). A call with SIZEOF()-1 is possible.
Incorrect use of OpconStrCat
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := SIZEOF(_tempString1), pAppendStr := ADR(_tempString2), AppendStrLen := SIZEOF(_tempString2));
Correct use of OpconStrCat
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := SIZEOF(_tempString1)-1, pAppendStr := ADR(_tempString2), AppendStrLen := SIZEOF(_tempString2)-1);
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := TEMP_STRING_1_LEN, pAppendStr := ADR(_tempString2), AppendStrLen := TEMP_STRING_2_LEN);
As all other OpconStr functions expect the actual string length as input parameter, OpconStrCat can also be used with it. OpconStrCat calls OpconStrLen again internally, which is why the use of OpconStrLen is optional.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)-1), pAppendStr := ADR(_tempString2), AppendStrLen := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)-1));
Explanation
When the transferred maximum string length is reached, these two functions write a 0 (null) as a string terminator in the subsequent memory area. If SIZEOF() is used without -1, this memory area lies outside the target string variable, e.g. on another variable or on the call stack. This leads to unnoticed misbehavior, unexpected variable values, page fault exceptions or TwinCAT changes directly from the RUN state to CONFIG without an error message.
The following online display "Value of the expression cannot be retrieved" can be an indication of such faulty memory operations:
String size and string length have a different meaning, as a string always requires a terminator null in addition to the characters:
VAR _tempString1 : STRING(TEMP_STRING_1_LEN); _tempString2 : STRING; END_VAR VAR CONSTANT TEMP_STRING_1_LEN : UDINT := 255; END_VAR _size := SIZEOF(_tempString1); // = 256 _length := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)); // = 0..255 (number of characters used) _size := SIZEOF(_tempString2); // = 81 _length := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)); // = 0..80 (number of characters used)
Possible use of OpconStrCat with disadvantages
If the string length is changed in the declaration of _tempString1 or _tempString2, you must also remember to change these code positions. According to the coding directives, constants should be used.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := 255, pAppendStr := ADR(_tempString2), AppendStrLen := 80);
According to the coding guidelines, only OpconStr functions should be used. Like all other string functions, LEN is limited to 255 characters. Contrary to the coding guidelines, you could then also use CONCAT instead of OpconStrCat.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := INT_TO_UDINT(LEN(_tempString1)), pAppendStr := ADR(_tempString2), AppendStrLen := INT_TO_UDINT(LEN(_tempString2)));
Hints about other string functions
OpconStrLen This function works with both SIZEOF() and SIZEOF()-1, as it only determines the actual string length. If the terminator null is missing, it is safer to use SIZEOF()-1 or a constant for the string length.
OpconStrLen(pString := ADR(_tempString1), MaxLen := SIZEOF(_tempString1)-1);
OpconStrLen(pString := ADR(_tempString1), MaxLen := TEMP_STRING_1_LEN);
OpconStrTrim When called with SIZEOF(), it is also written outside the memory area of the string variable. This function expects the actual string length as a input parameter, as otherwise an invalid string may be returned as the result. In contrast to OpconStrCat, OpconStrLen is not called internally. Therefore, only the following usage is correct:
OpconStrTrim(pString := ADR(_tempString1), StrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)));
OpconStrCmp (String Compare), OpconStrDelete, OpconStrFind, OpconStrToLower, OpconStrToUpper These functions expect the actual string length as a input parameter, otherwise an incorrect result will be returned. OpconStrLen must therefore be used to determine the string length.
OpconStrCmp(pString1 := ADR(_tempString1), String1Len := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)), pString2 := ADR(_tempString2), String2Len := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)));
Deutsch
🠦 English
Die Nexeed String-Funktion OpconStrCat() für String-Verknüpfung darf nicht mit SIZEOF() aufgerufen werden. Ein Aufruf mit SIZEOF()-1 ist möglich.
Fehlerhafte Anwendung von OpconStrCat
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := SIZEOF(_tempString1), pAppendStr := ADR(_tempString2), AppendStrLen := SIZEOF(_tempString2));
Korrekte Anwendung von OpconStrCat
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := SIZEOF(_tempString1)-1, pAppendStr := ADR(_tempString2), AppendStrLen := SIZEOF(_tempString2)-1);
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := TEMP_STRING_1_LEN, pAppendStr := ADR(_tempString2), AppendStrLen := TEMP_STRING_2_LEN);
Da alle anderen OpconStr-Funktionen die tatsächliche Stringlänge als Übergabe-Parameter erwarten, kann man auch OpconStrCat damit verwenden. OpconStrCat ruft intern nochmals OpconStrLen auf, weshalb die Verwendung von OpconStrLen optional ist.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)-1), pAppendStr := ADR(_tempString2), AppendStrLen := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)-1));
Erklärung
Bei Erreichen der übergebenen maximalen Stringlänge schreiben diese zwei Funktionen in den darauffolgenden Speicherbereich eine 0 (Null) als String-Terminator. Bei Verwendung von SIZEOF() ohne -1 liegt dieser Speicherbereich außerhalb der Ziel-String-Variable, z.B. auf einer anderen Variable oder auf dem Call Stack. Dies führt zu unbemerktem Fehlverhalten, unerwarteten Variablenwerten, Page Fault Exceptions (Ausnahmefehler) oder TwinCAT wechselt direkt vom Zustand RUN in CONFIG ohne Fehlermeldung.
Folgende Online-Darstellung "Value of the expression cannot be retrieved" kann ein Hinweis auf derartige fehlerhafte Speicheroperationen sein:
String-Größe und String-Länge haben eine unterschiedliche Bedeutung, da ein String immer zusätzlich zu den String-Zeichen eine Terminator-Null benötigt:
VAR _tempString1 : STRING(TEMP_STRING_1_LEN); _tempString2 : STRING; END_VAR VAR CONSTANT TEMP_STRING_1_LEN : UDINT := 255; END_VAR _size := SIZEOF(_tempString1); // = 256 _length := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)); // = 0..255 (Anzahl der verwendeten Zeichen) _size := SIZEOF(_tempString2); // = 81 _length := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)); // = 0..80 (Anzahl der verwendeten Zeichen)
Funktionierende Anwendungen von OpconStrCat mit Nachteilen
Wenn die Stringlänge in der Deklaration von _tempString1 bzw. _tempString2 geändert wird, muss man daran denken, diese Code-Stellen auch zu ändern. Laut Codierrichtlinien sollen Konstanten verwendet werden.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := 255, pAppendStr := ADR(_tempString2), AppendStrLen := 80);
Laut Codierrichtlinien sollen nur OpconStr-Funktionen verwendet werden. LEN ist wie alle anderen String-Funktionen auf 255 Zeichen begrenzt. Man könnte dann entgegen der Codierrichtlinien auch CONCAT anstatt OpconStrCat verwenden.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := INT_TO_UDINT(LEN(_tempString1)), pAppendStr := ADR(_tempString2), AppendStrLen := INT_TO_UDINT(LEN(_tempString2)));
Hinweise zu weiteren String-Funktionen
OpconStrLen Diese Funktion funktioniert sowohl mit SIZEOF() als auch mit SIZEOF()-1, da sie nur die tatsächliche Stringlänge ermittelt. Falls die Terminator-Null fehlt, ist die Verwendung mit SIZEOF()-1 oder Konstante für die Stringlänge sicherer.
OpconStrLen(pString := ADR(_tempString1), MaxLen := SIZEOF(_tempString1)-1);
OpconStrLen(pString := ADR(_tempString1), MaxLen := TEMP_STRING_1_LEN);
OpconStrTrim Bei Aufruf mit SIZEOF() wird ebenfalls außerhalb des Speicherbereichs der String-Variable geschrieben. Diese Funktion erwartet die tatsächliche Stringlänge als Übergabeparameter, da ansonsten ein ungültiger String als Ergebnis ausgegeben werden kann. Im Gegensatz zu OpconStrCat erfolgt kein interner Aufruf von OpconStrLen. Deshalb ist nur folgende Anwendung korrekt:
OpconStrTrim(pString := ADR(_tempString1), StrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)));
OpconStrCmp (String Compare), OpconStrDelete, OpconStrFind, OpconStrToLower, OpconStrToUpper Diese Funktionen erwarten die tatsächliche Stringlänge als Übergabeparameter, da ansonsten ein falsches Ergebnis geliefert wird. Es muss deshalb OpconStrLen zur Ermittlung der Stringlänge verwendet werden.
OpconStrCmp(pString1 := ADR(_tempString1), String1Len := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)), pString2 := ADR(_tempString2), String2Len := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)));
... View more