Strange method behavior, it will work locally, but not as an object
turbosupra
Posts: 1,088
I'm using Kye's strings method and when I send the following I'm getting strange behavior and was hoping someone could shed some light as to why. I tried to make this as simple as possible, but if it is confusing, I'll be happy to post my entire code, please let me know.
Whenever I send a string that has 2 or more characters in front of the delimiterPositionForName (in this case an equals sign) it will work
So 01=mot or 44=mot
But anytime I run it as an object and it is a single digit, it will not find the delimiter and returns a -1.
when I run it locally
Does anyone have any theories as to why? Thanks for reading.
This code below always works locally or as a method because there are at least 2 characters in front of the delimiter, in this case "31".
Whenever I send a string that has 2 or more characters in front of the delimiterPositionForName (in this case an equals sign) it will work
So 01=mot or 44=mot
But anytime I run it as an object and it is a single digit, it will not find the delimiter and returns a -1.
[b]DOESN'T WORK[/b] OBJ pst : "Parallax Serial Terminal" strings : "Strings" com : "serialCom" l_variableReversed := "3=mot" b_delimiter[0] := "=" b_delimiter[1] := 0 l_returnTemp := strings.StrPos(l_variableReversed, @b_delimiter, 0) l_returnTemp is -1 (or it cannot find it)
when I run it locally
[b]DOES WORK[/b] OBJ pst : "Parallax Serial Terminal" strings : "Strings" com : "serialCom" l_variableReversed := "3=mot" b_delimiter[0] := "=" b_delimiter[1] := 0 l_returnTemp := StrPos(l_variableReversed, @b_delimiter, 0) l_returnTemp is 1
Does anyone have any theories as to why? Thanks for reading.
This code below always works locally or as a method because there are at least 2 characters in front of the delimiter, in this case "31".
[b]ALWAYS WORKS[/b] OBJ pst : "Parallax Serial Terminal" strings : "Strings" com : "serialCom" l_variableReversed := "31=mot" (or anything that is more than 1 digit) b_delimiter[0] := "=" b_delimiter[1] := 0 l_returnTemp := strings.StrPos(l_variableReversed, @b_delimiter, 0) OR l_returnTemp := StrPos(l_variableReversed, @b_delimiter, 0)
Comments
l_variableReversed := string("31=mot")
This sets l_variableReversed to the address of the first byte of the string which is what you want here. The string is stored as a byte array with a zero byte appended to it to mark the end.
Thanks for the reply that was a typo, I apologize for that. Since I was trying to simply my code, I missed that when typing.
The work firewall is blocking me from uploading the method object.
So why if I call this method as an attached object and strAddr (in the method below) starts with a single numeric value before the delimiter, will the method fail ... but if strAddr starts with 2 or more numeric values, will the method succeed?
Then when I call it locally, it works with a single digit?
I can post my entire code, just not as an attached set of files, if that helps.
I believe this indicates what the problem is, although I'm not 100% sure yet what it is.
I'm getting "3=mot" as a return value from another method. It is a variable that is set to a long (l_variableReversed ). In my example I hard coded it to simplify how long the code was and to try and make it easier to understand (which is where the typo came from). When I hard coded it like your example, it did indeed work.
The difference is between
(long) l_variableReversed := string("3=mot")
and (long) l_variableReversed := method return value, which I believe is a "long"
Can anyone expand upon this and tell me if I'm onto something or not? If this is indeed the issue, how can I correct it?
When you use the Strings object, ostr is allocated in the storage area for the object. When you use the StrParse method locally, you have to provide that and it has to be big enough to hold the largest possible result string.
Also, can you explain the programmatic difference between these two? Is there a "toString" method, so I could say l_variableReversed := l_variableReversed.ToString or something like that?
(long) l_variableReversed := string("3=mot")
and (long) l_variableReversed := method return value, which I believe is a "long"
Spin does not really have string values. It has 32-bit signed integers that are called longs. There are 16-bit variables (words) and 8-bit variables (bytes) as well as arrays of all of these. No automatic sign extension is done when fetching values from storage units smaller than 32-bits. String constants are stored as byte arrays with a zero byte as a terminator and the address of the first byte is what is used as the string "value". Various library routines that use string values (like the String object) use the same convention. Method parameters, results, and local variables are all longs.
Spin does allow single quoted characters in expressions and the value of that quoted character is the numeric value of the character in the ASCII character set. StrPos expects its first two parameters to be strings, in other words, the addresses of characters stored in byte arrays in memory. You would call StrPos as follows:
outa[16..23] := strings.StrPos(string("3=mot"), string("="), 0)
If you declare
var byte l_stringReversed[10], delimiter[3]
var long l_variableReversed
you could then write (in some method)
l_variableReversed := @l_stringReversed ' get the address of the string value
bytemove(l_variableReversed, string("3=mot"), 6) ' initialize the string value
bytemove(@delimiter, string("="), 2) ' initialize the delimiter value
dira[ 16..23 ]~~
outa[ 16..23 ] := StrPos( l_variableReversed, @delimiter, 0 )
Hi Mike,
Thanks for the reply. The strange behavior is that when I use the StrPos (and StrParse) methods locally, they will work regardless of how many characters/bytes precede the delimiter in the StrPos method.
When I use the StrPos method by attaching it inside of the Strings object (Strings.StrPos)
it will only work if the character/byte count is 2 or more, that precede the delimiter in the Strings.StrPos method.
If I understand this correctly, if a string is "This is a string", the variable would be stringName[128] and the string method would want the memory address of the first "T". After that, it would read each concurrent byte, until it arrived at a byte with all zeros, 00000000 and that is how it determines the length of the string byte array and where it ends, correct?
This is because it stores it as a single byte, followed by a byte terminator of 00000000 ?
I will have to try this code. Would you mind if I emailed you my code, so you could see the changing behavior?
"Spin does allow single quoted ..." No, the constant value is actually encoded in the Spin interpretive instructions since there's an instruction that does a push immediate value for 8-bit values. There's no byte terminator since this really isn't considered a string, just a single character value.