English | 🠦 Deutsch |
The Nexeed string function OpconStrCat() for string concatenation must not be called with SIZEOF(). A call with SIZEOF()-1 is possible.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := SIZEOF(_tempString1),
pAppendStr := ADR(_tempString2), AppendStrLen := SIZEOF(_tempString2));
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);
OpconStrCat(pDestStr := ADR(_tempString1),
DestStrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)-1),
pAppendStr := ADR(_tempString2),
AppendStrLen := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)-1));
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)
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := 255,
pAppendStr := ADR(_tempString2), AppendStrLen := 80);
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := INT_TO_UDINT(LEN(_tempString1)),
pAppendStr := ADR(_tempString2), AppendStrLen := INT_TO_UDINT(LEN(_tempString2)));
OpconStrLen(pString := ADR(_tempString1), MaxLen := SIZEOF(_tempString1)-1);
OpconStrLen(pString := ADR(_tempString1), MaxLen := TEMP_STRING_1_LEN);
OpconStrTrim(pString := ADR(_tempString1),
StrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)));
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.
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := SIZEOF(_tempString1),
pAppendStr := ADR(_tempString2), AppendStrLen := SIZEOF(_tempString2));
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);
OpconStrCat(pDestStr := ADR(_tempString1),
DestStrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)-1),
pAppendStr := ADR(_tempString2),
AppendStrLen := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)-1));
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)
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := 255,
pAppendStr := ADR(_tempString2), AppendStrLen := 80);
OpconStrCat(pDestStr := ADR(_tempString1), DestStrLen := INT_TO_UDINT(LEN(_tempString1)),
pAppendStr := ADR(_tempString2), AppendStrLen := INT_TO_UDINT(LEN(_tempString2)));
OpconStrLen(pString := ADR(_tempString1), MaxLen := SIZEOF(_tempString1)-1);
OpconStrLen(pString := ADR(_tempString1), MaxLen := TEMP_STRING_1_LEN);
OpconStrTrim(pString := ADR(_tempString1),
StrLen := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)));
OpconStrCmp(pString1 := ADR(_tempString1),
String1Len := OpconStrLen(ADR(_tempString1), SIZEOF(_tempString1)),
pString2 := ADR(_tempString2),
String2Len := OpconStrLen(ADR(_tempString2), SIZEOF(_tempString2)));