<> Not Equal To != ?
Someone asked me why I use "<>" instead of "!=". The Reference states that "<>" is the operator for "Not Equal To" so I've always used that. However some people use "!=", and even some code examples in the Reference uses "!=", and clearly they perform the same function.
However, operator precedence states "!" has the highest precedence of any operator, Level 1, whereas "<>" is down at Level 5. The "=" is also at Level 5, right before "==" and "<>".
Could using one over the other cause logic problems? It could just be unpublished that "!=" is automatically compiled to mean "<>" and thereby always has the same precedence. Perhaps the code in which the precedence of "!" changes the result when combined with "=" is simply un-writable.
However, operator precedence states "!" has the highest precedence of any operator, Level 1, whereas "<>" is down at Level 5. The "=" is also at Level 5, right before "==" and "<>".
Could using one over the other cause logic problems? It could just be unpublished that "!=" is automatically compiled to mean "<>" and thereby always has the same precedence. Perhaps the code in which the precedence of "!" changes the result when combined with "=" is simply un-writable.
0
Comments
I wish there was a "Like" button for your title..
I cant speak for if it changes while compiling, but by habbit I use "!=" and have never had any issues.
My .02
Using != burned me once so I stopped using it for not equal to and only use <> now. != actually is different than <>. It means, check if the right side is equivalent to the not of the left side. Usually this works, but not always. Break the habit if you can, to write bug free code.
Paul
I'll see if I can find it, but it was a couple of years ago and my memory is foggy about what the code was. But it was a subtle bug, and took me a while to figure out, so I was pissed that it was caused by what would have worked in almost every other language.
Paul
EDIT: This was hashed out some time ago
http://www.amxforums.com/showthread.php?3631-!-gotcha&highlight=not+equal+to
I've ran into issues with != myself too. At the time I just wrote it off to one of those pesky integer 'really' being evaluated as a long for some reasons or other. A lot of times I have to curb my curiosity about why something works or doesn't for getting the job done and over.
IE:
integer iZero = 0 integer iTwo = 2 if (iZero != iTwo) { doSomething() }We know 0 is not equal to 2 so this should always evaluate to true and doSomething gets called. But I think what happened in my case was the bang flipped 0 to 1 and then checked to see if 1 = 2 which is false of course, and so it evaluates to false and doSomething doesn't get called like it should. I can't test it at the moment but I seem to recall it was something like this that got me.
Paul
+1. (Plus other stuff to make the message long enough).
In the below tests I see nothing to make me think that the compiler isn't taking the != combination and translating to <>. The only odd thing this test revealed is when I assigned my two chars.
STACK_VAR CHAR cChar1;
STACK_VAR CHAR cChar2;
cChar1 = '';
cChar2 = '';
When I print to diagnostics I get:
Line 23 (17:30:08):: TEST cChar1-[ @ ] & cChar2-[ @ ] :DEBUG<297>
Not sure what's up with that but everything else regarding != seems to work just like <> with no odd behavior.
The Code:
DEFINE_PROGRAM if(nTestRun) { STACK_VAR INTEGER nIntNum1; STACK_VAR INTEGER nIntNum2; STACK_VAR LONG nLongNum1; STACK_VAR LONG nLongNum2; STACK_VAR CHAR cChar1; STACK_VAR CHAR cChar2; STACK_VAR CHAR cStr1[12]; STACK_VAR CHAR cStr2[12]; nIntNum1 = 6; nIntNum2 = 6; nLongNum1 = 66000; nLongNum2 = 66000; cChar1 = 'a'; cChar2 = 'a'; cStr1 = 'test'; cStr2 = 'test'; if(nIntNum1 != nIntNum2) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum1 != nLongNum2) SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] != nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] == nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cChar2) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr1 != cStr2) SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] != cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] == cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 2; nIntNum2 = 6; nLongNum1 = 1; nLongNum2 = 66000; cChar1 = 'z'; cChar2 = 'a'; cStr1 = 'dog'; cStr2 = 'cat'; if(nIntNum1 != nIntNum2) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum1 != nLongNum2) SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] != nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] == nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cChar2) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr1 != cStr2) SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] != cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] == cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 0; nIntNum2 = 10; nLongNum1 = 0; nLongNum2 = 28800; cChar1 = '0'; cChar2 = '1'; cStr1 = '0'; cStr2 = '5'; if(nIntNum1 != nIntNum2) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum1 != nLongNum2) SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] != nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] == nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cChar2) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr1 != cStr2) SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] != cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] == cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 0; nIntNum2 = 10; nLongNum1 = 0; nLongNum2 = 10; cChar1 = 'a'; cChar2 = 'z'; cStr1 = 'a'; cStr2 = 'z'; if(nIntNum1 != nLongNum1) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nLongNum1-[ ',itoa(nLongNum1),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nLongNum1-[ ',itoa(nLongNum1),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum2 != nIntNum2) SEND_STRING 0,"'TEST nLongNum2-[ ',itoa(nLongNum2),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum2),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cStr1) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cStr1-[ ',cStr1,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cStr1-[ ',cStr1,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr2 != cChar2) SEND_STRING 0,"'TEST cStr2-[ ',cStr2,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr2-[ ',cStr2,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 2; nIntNum2 = 0; nLongNum1 = 0; nLongNum2 = 10; cChar1 = 'c'; cChar2 = 'd'; cStr1 = 'cat'; cStr2 = 'dog'; if(nIntNum1 != nLongNum1) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nLongNum1-[ ',itoa(nLongNum1),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nLongNum1-[ ',itoa(nLongNum1),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum2 != nIntNum2) SEND_STRING 0,"'TEST nLongNum2-[ ',itoa(nLongNum2),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum2),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cStr1) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cStr1-[ ',cStr1,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cStr1-[ ',cStr1,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr2 != cChar2) SEND_STRING 0,"'TEST cStr2-[ ',cStr2,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr2-[ ',cStr2,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 0; nIntNum2 = 0; nLongNum1 = 0; nLongNum2 = 0; cChar1 = ''; cChar2 = ''; cStr1 = ''; cStr2 = ''; if(nIntNum1 != nIntNum2) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum1 != nLongNum2) SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] != nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] == nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] & cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cChar2) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr1 != cStr2) SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] != cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] == cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 0; nIntNum2 = 2; nLongNum1 = 0; nLongNum2 = 2; cChar1 = 'a'; cChar2 = 'z'; cStr1 = 'z'; cStr2 = 'a'; if(nIntNum1 != nIntNum2) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum1 != nLongNum2) SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] != nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] == nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cChar2) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr1 != cStr2) SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] != cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] == cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; nIntNum1 = 0; nIntNum2 = 1; nLongNum1 = 1; nLongNum2 = 0; cChar1 = 'z'; cChar2 = 't'; cStr1 = 'zoo'; cStr2 = 'test'; if(nIntNum1 != nIntNum2) SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] != nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nIntNum1-[ ',itoa(nIntNum1),' ] == nIntNum2-[ ',itoa(nIntNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(nLongNum1 != nLongNum2) SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] != nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST nLongNum1-[ ',itoa(nLongNum1),' ] == nLongNum2-[ ',itoa(nLongNum2),' ] :DEBUG<',itoa(__LINE__),'>'"; if(cChar1 != cChar2) SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] != cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cChar1-[ ',cChar1,' ] == cChar2-[ ',cChar2,' ] :DEBUG<',itoa(__LINE__),'>'"; if(cStr1 != cStr2) SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] != cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cStr1-[ ',cStr1,' ] == cStr2-[ ',cStr2,' ] :DEBUG<',itoa(__LINE__),'>'"; nTestRun = 0; }You have two variables each of which is a one-byte integer. I have no idea what happens when you try to assign '' (i.e., nothing) to a one-byte integer. Does it actually change the value stored in the byte in memory referred to?
When you do the comparison, you're telling the processor to compare the values stored in each of the bytes referred to and I just don't know what those values would be after the assignment to ''.
Perhaps if you assign equal values to the variables and then try to null them and then compare using != and then assign different one-byte values and then null them and then compare. My suspicion is that the assignment to '' has no effect.
Otherwise, I think you and I agree on what != is all about. That is, that it can be used interchangeably with <>. We went through all this a couple years ago and that's my recollection. Also, nobody has actually found a case where <> and != give different results, have they?
IE:
define_device dev vdvDevice = 0:0:0 dev vdvTest = 0:0:0 dev vdvTV = 31001:1:1 define_program if(vdvTV != vdvDevice ) { doSomething() } if(vdvTV <> vdvDevice ) { doSomething() } if(vdvTest != vdvDevice ) { doSomething() } if(vdvTest <> vdvDevice ) { doSomething() }Can you add a device to your test code?
Paul
DEFINE_DEVICE //VIRTUALS vdvDevice = 0:0:0 vdvTest = 0:0:0 vdvTV = 31001:1:1 DEFINE_PROGRAM if(nTestRun) { if(vdvTV != vdvDevice) SEND_STRING 0,"'TEST vdvTV-[ ',fnDEV_TO_STRING(vdvTV),' ] != vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST vdvTV-[ ',fnDEV_TO_STRING(vdvTV),' ] == vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; if(vdvTV <> vdvDevice) SEND_STRING 0,"'TEST vdvTV-[ ',fnDEV_TO_STRING(vdvTV),' ] <> vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST vdvTV-[ ',fnDEV_TO_STRING(vdvTV),' ] == vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; if(vdvTest != vdvDevice) SEND_STRING 0,"'TEST vdvTest-[ ',fnDEV_TO_STRING(vdvTest),' ] != vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST vdvTest-[ ',fnDEV_TO_STRING(vdvTest),' ] == vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; if(vdvTest <> vdvDevice) SEND_STRING 0,"'TEST vdvTest-[ ',fnDEV_TO_STRING(vdvTest),' ] <> vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST vdvTest-[ ',fnDEV_TO_STRING(vdvTest),' ] == vdvDevice-[ ',fnDEV_TO_STRING(vdvDevice),' ] :DEBUG<',itoa(__LINE__),'>'"; nTestRun = 0; }results:
Looking through my code I was using arrays. Not sure if that will make any difference.
My code looked something like this:
define_device vdvNull = 0:0:0 if(dvDevices[1][1] != vdvNull) { doSomething() }I called the problem into AMX TS so the possibility exists they were able to correct it in a subsequent firmware release. This occurred back in 2009.
Paul
Here's what I've come up with in testing. Note that a few of the tests were not 100% specific to the question at hand, however, I thought they might be helpful in trying to find a discrepancy in != and <>.
The code
http://pastebin.com/dve00sKi
The results
Master Type: NI-3100
Master Firmware: v4.1.373
Device Firmware: v1.30.10
http://pastebin.com/Cxr2xg2s
Master Type: NI-2000
Master Firmware: v3.50.430
Device Firmware: v1.13.7
http://pastebin.com/j808uykY
I then downgraded the master firmware
Master Type: NI-2000
Master Firmware: v2.32.148
Device Firmware: v1.12.140
http://pastebin.com/QyD9mM8P
Unless there is something I missed, which is very possible, I don't see any difference between firmware versions. Perhaps my tests were too weak. I'll be happy to test on an array of firmwares if it means getting to the bottom of this.
I use it in multiple languages. I've never liked using <> .. it reminds me of GWbasic or something. != is always a true C expression for me.
Never failed as != .. never.
for example, there are times when I wish to stop an 'if' block from running. So instead of commenting or editing out the block, I'll simply change the qualifier to if(1!=1) and the block will be skipped.
and the bottom line is, try to avoid 'if' statements. If you are using 'swtich' blocks, then the problem will not arise at all - i believe.
like others have said, just my 2 cents worth.
yes, of course your right.. i'm talking about a habit that creates a visual guide for me.. i can always recognise why i did something if i used that 1!=1
bloody programmers, ten thousand one hundred and five million ways to open a bottle top
Paul
No, no, no.
!= is a single operator equivalent to the netlinx not equal ccomparative <>. =! Is two separate operators.
=!, when you are looking at it as a comparative, first executes the !, because of the precedence. Then it does the comparative evaluation. Compare:
If(2!=3)
and
If(2=!3)
Sounds like you could use IF (0=!5) or IF (TRUE =! FALSE) for TRUE statements
It looks to me like this really boils down to: we have to see the code that invoked the bug. It's entirely possible that something else is causing the problem.
For example:
I have recently been bitten by a string evaluation "feature" where only the first byte of the string is used. This happens when a string is used where a number is expected.
What I was trying to do was check if a string had something in it, and initially wrote the code little too carelessly:
IF (string) { // do something }The problem was - it sometimes evaluated as TRUE even if the string had no length.
This compiles fine, and works most of the time.
What happened was if the first byte of the string was non-0, then it would do something – even if the length of the string was 0.
This was the fix:
IF (LENGTH_ARRAY(string)) { // do something }Here's another example that uses not-equals operators:
CHAR str[] = "1,2,3,4,5" IF (str <> 1) { // do something } ELSE { // do something else }Guess what happens?p.s. The same thing happens when you do this:
IF (str != 1) { // do something } ELSE { // do something else }Change the first byte of str to 0 - the other leg will execute.That's always a possibility. My memory tells me that I spent a long time testing that code and I ended up having to put a lot of send_strings in there to finally figure it out. I called AMX TS and was told that != isn't actually the correct operator for not equal to, and once I switched to <> the bug disappeared. From what I recall, the bug only occurred for a specific value, so it worked 99% of the time, making it even more difficult to debug. Anyway, if you have total confidence that != works in every case, use it. I'm sticking with <>
Paul
I think I've seen this happen when a variable is created but not set to any value. If there's something already in the memory allocated for the variable you can get random junk in there which will cause the array to evaluate as true.
apparently, if(string) is the same as if(string[1]). If what you want to do is determine if there is any valid value assigned to the string, this doesn't really do the trick. One reason is as already noted -- just because the string has no length doesn't mean that there is a zero value stored in the memory assigned to string[1]. Another problem is that it is perfectly fine to have a valid string with the first element being assigned zero. "0,'this is a valid string',$0d "
for example.
Something else that can cause difficulty is using a device array on the right hand side.
[vdvTPArray,nButton] = ![vdvTPArray,nButton]
may not give the desired result, for example.
This is a good point. I'll usually check for empty arrays like this:
or
Since I had the other test set up still I modified it to help me get my head warapped around this issue and here's what I got:
Line 1 (18:17:23):: Initialized values Line 2 (18:17:23):: VOLATILE CHAR cTestStr[5] Line 3 (18:17:23):: VOLATILE CHAR cTestStr_Init[5] = {1,2,3,4,5} Line 4 (18:17:23):: VOLATILE CHAR cTestStr_Init_0[5] = {0,0,0,0,0} Line 5 (18:17:23):: VOLATILE CHAR cTestStr_Init_0_1[5] = {0,1,1,1,1} Line 6 (18:17:23):: . Line 7 (18:17:23):: TEST cTestStr-[ has no value ] :DEBUG<155> Line 8 (18:17:23):: TEST cTestStr_Init-[ has value ] :DEBUG<158> Line 9 (18:17:23):: TEST cTestStr_Init_0-[ has no value ] :DEBUG<165> Line 10 (18:17:23):: TEST cTestStr_Init_0_1-[ has no value ] :DEBUG<170> Line 11 (18:17:23):: . Line 12 (18:17:23):: .. Line 13 (18:17:23):: ... Line 14 (18:17:23):: SET_LENGTH_STRING(cTestStr,5) Line 15 (18:17:23):: SET_LENGTH_STRING(cTestStr_Init,0) Line 16 (18:17:23):: . Line 17 (18:17:23):: TEST cTestStr-[ has no value ] :DEBUG<182> Line 18 (18:17:23):: TEST cTestStr_Init-[ has value ] :DEBUG<185> Line 19 (18:17:23):: . Line 20 (18:17:23):: .. Line 21 (18:17:23):: ... Line 22 (18:17:23):: cTestStr = "1,2,3,4,5" Line 23 (18:17:23):: cTestStr_Init = "1,2,3,4,5" Line 24 (18:17:23):: . Line 25 (18:17:23):: TEST cTestStr-[ has value ] :DEBUG<197> Line 26 (18:17:23):: TEST cTestStr_Init-[ has value ] :DEBUG<202> Line 27 (18:17:23):: . Line 28 (18:17:23):: .. Line 29 (18:17:23):: ... Line 30 (18:17:23):: cTestStr = "1,2,3,4,5" Line 31 (18:17:23):: cTestStr_Init = "1,2,3,4,5" Line 32 (18:17:23):: SET_LENGTH_STRING(cTestStr,5) Line 33 (18:17:23):: SET_LENGTH_STRING(cTestStr_Init,5) Line 34 (18:17:23):: . Line 35 (18:17:23):: TEST cTestStr-[ has value ] :DEBUG<218> Line 36 (18:17:23):: TEST cTestStr_Init-[ has value ] :DEBUG<223> Line 37 (18:17:23):: . Line 38 (18:17:23):: .. Line 39 (18:17:23):: ... Line 40 (18:17:23):: SET_LENGTH_STRING(cTestStr,0) Line 41 (18:17:23):: SET_LENGTH_STRING(cTestStr_Init,0) Line 42 (18:17:23):: cTestStr = "0,2,3,4,5" Line 43 (18:17:23):: cTestStr_Init = "0,2,3,4,5" Line 44 (18:17:23):: . Line 45 (18:17:23):: TEST cTestStr-[ has no value ] :DEBUG<241> Line 46 (18:17:23):: TEST cTestStr_Init-[ has no value ] :DEBUG<246> Line 47 (18:17:23):: . Line 48 (18:17:23):: .. Line 49 (18:17:23):: ... Line 50 (18:17:23):: cTestStr = "0,2,3,4,5" Line 51 (18:17:23):: cTestStr_Init = "0,2,3,4,5" Line 52 (18:17:23):: SET_LENGTH_STRING(cTestStr,5) Line 53 (18:17:23):: SET_LENGTH_STRING(cTestStr_Init,5) Line 54 (18:17:23):: . Line 55 (18:17:23):: TEST cTestStr-[ has no value ] :DEBUG<262> Line 56 (18:17:23):: TEST cTestStr_Init-[ has no value ] :DEBUG<267> Line 57 (18:17:23):: . Line 58 (18:17:23):: .. Line 59 (18:17:23):: ... Line 60 (18:17:23):: SET_LENGTH_STRING(cTestStr,5) Line 61 (18:17:23):: SET_LENGTH_STRING(cTestStr_Init,5) Line 62 (18:17:23):: cTestStr = '' Line 63 (18:17:23):: cTestStr_Init = '' Line 64 (18:17:23):: . Line 65 (18:17:23):: TEST cTestStr-[ has no value ] :DEBUG<283> Line 66 (18:17:23):: TEST cTestStr_Init-[ has no value ] :DEBUG<288> Line 67 (18:17:23):: . Line 68 (18:17:23):: .. Line 69 (18:17:23):: ... Line 70 (18:17:23):: cTestStr = "0,2,3,4,5" Line 71 (18:17:23):: cTestStr_Init = "0,2,3,4,5 Line 72 (18:17:23):: cTestStr = '' Line 73 (18:17:23):: cTestStr_Init = '' Line 74 (18:17:23):: SET_LENGTH_STRING(cTestStr,0) Line 75 (18:17:23):: SET_LENGTH_STRING(cTestStr_Init,0) Line 76 (18:17:23):: . Line 77 (18:17:23):: TEST cTestStr-[ has no value ] :DEBUG<308> Line 78 (18:17:23):: TEST cTestStr_Init-[ has no value ] :DEBUG<313>if anyone wants to modify the test here's the code.DEFINE_VARIABLE //testing VOLATILE INTEGER nTestRun; VOLATILE CHAR cTestStr[5]; VOLATILE CHAR cTestStr_Init[5] = {1,2,3,4,5}; VOLATILE CHAR cTestStr_Init_0[5] = {0,0,0,0,0}; VOLATILE CHAR cTestStr_Init_0_1[5] = {0,1,1,1,1}; DEFINE_PROGRAM if(nTestRun) { SEND_STRING 0,"'Initialized values'"; SEND_STRING 0,"'VOLATILE CHAR cTestStr[5]'"; SEND_STRING 0,"'VOLATILE CHAR cTestStr_Init[5] = {1,2,3,4,5}'"; SEND_STRING 0,"'VOLATILE CHAR cTestStr_Init_0[5] = {0,0,0,0,0}'"; SEND_STRING 0,"'VOLATILE CHAR cTestStr_Init_0_1[5] = {0,1,1,1,1}'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init_0) SEND_STRING 0,"'TEST cTestStr_Init_0-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init_0-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init_0_1) SEND_STRING 0,"'TEST cTestStr_Init_0_1-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init_0_1-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; SET_LENGTH_STRING(cTestStr,5); SET_LENGTH_STRING(cTestStr_Init,0); SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr,5)'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr_Init,0)'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; cTestStr = "1,2,3,4,5"; cTestStr_Init = "1,2,3,4,5"; SEND_STRING 0,"'cTestStr = "1,2,3,4,5"'"; SEND_STRING 0,"'cTestStr_Init = "1,2,3,4,5"'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; cTestStr = "1,2,3,4,5"; cTestStr_Init = "1,2,3,4,5"; SET_LENGTH_STRING(cTestStr,5); SET_LENGTH_STRING(cTestStr_Init,5); SEND_STRING 0,"'cTestStr = "1,2,3,4,5"'"; SEND_STRING 0,"'cTestStr_Init = "1,2,3,4,5"'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr,5)'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr_Init,5)'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; SET_LENGTH_STRING(cTestStr,0); SET_LENGTH_STRING(cTestStr_Init,0); cTestStr = "0,2,3,4,5"; cTestStr_Init = "0,2,3,4,5"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr,0)'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr_Init,0)'"; SEND_STRING 0,"'cTestStr = "0,2,3,4,5"'"; SEND_STRING 0,"'cTestStr_Init = "0,2,3,4,5"'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; cTestStr = "0,2,3,4,5"; cTestStr_Init = "0,2,3,4,5"; SET_LENGTH_STRING(cTestStr,5); SET_LENGTH_STRING(cTestStr_Init,5); SEND_STRING 0,"'cTestStr = "0,2,3,4,5"'"; SEND_STRING 0,"'cTestStr_Init = "0,2,3,4,5"'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr,5)'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr_Init,5)'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; SET_LENGTH_STRING(cTestStr,5); SET_LENGTH_STRING(cTestStr_Init,5); cTestStr = ''; cTestStr_Init = ''; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr,5)'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr_Init,5)'"; SEND_STRING 0,"'cTestStr = '''''"; SEND_STRING 0,"'cTestStr_Init = '''''"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; SEND_STRING 0,"'.'";SEND_STRING 0,"'..'";SEND_STRING 0,"'...'"; cTestStr = "0,2,3,4,5"; cTestStr_Init = "0,2,3,4,5"; cTestStr = ''; cTestStr_Init = ''; SET_LENGTH_STRING(cTestStr,0); SET_LENGTH_STRING(cTestStr_Init,0); SEND_STRING 0,"'cTestStr = "0,2,3,4,5"'"; SEND_STRING 0,"'cTestStr_Init = "0,2,3,4,5'"; SEND_STRING 0,"'cTestStr = '''''"; SEND_STRING 0,"'cTestStr_Init = '''''"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr,0)'"; SEND_STRING 0,"'SET_LENGTH_STRING(cTestStr_Init,0)'"; SEND_STRING 0,"'.'"; if(cTestStr) SEND_STRING 0,"'TEST cTestStr-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; if(cTestStr_Init) SEND_STRING 0,"'TEST cTestStr_Init-[ has value ] :DEBUG<',itoa(__LINE__),'>'"; else SEND_STRING 0,"'TEST cTestStr_Init-[ has no value ] :DEBUG<',itoa(__LINE__),'>'"; nTestRun = 0; }That being said, my test results showed that even doing a str = '' or set_length_string(str,0) resulted in a true condition.
My full test code was uploaded to PasteBin as well as the results in different "bins". (See this post.)
Here were the tests & results. Note: s_string had a value of '12' prior to Test 30.
send_string 0,'Test 30 ************************************'; s_string = ''; if(s_string) send_string 0,"'s_string == true'"; else send_string 0,"'s_string == false'"; send_string 0,"'length_string(s_string) == ',itoa(length_string(s_string))"; send_string 0,'Test 31 ************************************'; set_length_string(s_string,0); if(s_string) send_string 0,"'s_string == true'"; else send_string 0,"'s_string == false'"; send_string 0,"'length_string(s_string) == ',itoa(length_string(s_string))";I think would accomplish the same thing would it not? The != 0 is redundant.
Paul
Ya but for me the readability is improved by having the != in there.