Go Down

Topic: if statement evaluating complex expressions (Read 698 times) previous topic - next topic

yerg2k

Jan 22, 2008, 03:36 am Last Edit: Jan 22, 2008, 04:39 am by yerg2k Reason: 1
Hi fellow coders, I'm having trouble wrapping my mind around a confusing issue and need some clarification regarding how if statements are evaluating.

The following code works, but it shouldn't:
Code: [Select]
if ((preamble == 150) && ((curdata >> 16) == ~(curdata & 0xFFFF))) {
   return(curdata & 0xFFFF);
 }


In my transmitter code, the integer to be transmitted is shifted out, followed by its inverse. Here is the original thread in the hardware forum. In that thread,

Quote
I really don't know how it works like this.  If curdata == 0xAAAA5555 and you put it through

Code: [Select]
((curdata >> 16) == ~(curdata & 0xFFFF))

then (curdata >> 16) = 0x0000AAAA
and ~(curdata & 0xFFFF) = 0xFFFFAAAA

this is because curdata & 0xFFFF evaluates first giving 0x00005555, then the ~ is evaluated giving 0xFFFFAAAA.

I don't understand how that expression can ever evaluate to true. :(  If somebody knows that part of the puzzle please let me know!  [smiley=huh.gif]

you might want to try something like this:
Code: [Select]
(((curdata >> 16) & 0xFFFF) == (~curdata & 0xFFFF))


Again this code shouldn't work, but does. It is returning (curdata & 0xFFFF) which should be the real integer's inverse. But, it is returning the actual number sent from the transmitter.

The following code still works like above, but is properly put together and reads correctly:
Code: [Select]
   if ((preamble == 150) && ((curdata >> 16) == (~curdata & 0xFFFF))) {
     return(curdata >> 16);
   }  


The two code snippets work the same, except the former returns (curdata & 0xFFFF) which really should be the inverse of the actual number, and the latter code returns it properly (curdata >> 16). Something about the way the if statement evaluates, is causing it to work when it shouldn't. It has something to do with ~(expression) changing the value held in curdata methinks.

Could someone please explain why the code above works like it does? Thanks In Advance.

mem

#1
Jan 22, 2008, 08:10 am Last Edit: Jan 22, 2008, 08:11 am by mem Reason: 1
The code as written should and does work because curdata is really two consecutive integers treated as a long, where the second integer is equal to the first integer with the bits inverted

(curdata >> 16) == ~(curdata & 0xFFFF)

means that the non inverted int value ie :
  (curdata >> 16)
is the same as the second integer inverted
  (curdata & 0xFFFF) is the second integer and the tilde ~ inverts this, which undoes the inversion performed in the send.

I hope that makes sense.

yerg2k

So, then I guess both
(curdata >> 16)
and
~(curdata & 0xFFFF)
result in unsigned ints that get compared? If they resulted in unsigned long then the first statement would evaluate as 0000nnnn and the second as FFFFnnnn, since the leading 0's would be inverted. This is obviously not the case.

Regardless, it is working right in the "fixed" version with (~curdata & 0xFFFF) which is good.

mem

If you are interested in a peek at the assembler code the compiler produces here it is:
Code: [Select]
if ( ((curdata >> 16) == ~(curdata & 0xFFFF))) {
 e2:      29 81             ldd      r18, Y+1      ; 0x01  //load least significant byte of curdata
 e4:      3a 81             ldd      r19, Y+2      ; 0x02  // into working registers
 e6:      4b 81             ldd      r20, Y+3      ; 0x03
 e8:      5c 81             ldd      r21, Y+4      ; 0x04  // this is most significant byte
 ea:      89 81             ldd      r24, Y+1      ; 0x01  // this loads a copy of curdata
 ec:      9a 81             ldd      r25, Y+2      ; 0x02  //into another set of registers
 ee:      ab 81             ldd      r26, Y+3      ; 0x03
 f0:      bc 81             ldd      r27, Y+4      ; 0x04
 f2:      9a 01             movw      r18, r20             // move the upper two bytes to the lower (i.e. >>16)
 f4:      44 27             eor      r20, r20             // exclusive or upper bytes
 f6:      55 27             eor      r21, r21
 f8:      a0 70             andi      r26, 0x00      ; 0    // set the copy of upper bytes to 0
 fa:      b0 70             andi      r27, 0x00      ; 0
 fc:      80 95             com      r24                    // flip all the bits in the copy
 fe:      90 95             com      r25
100:      a0 95             com      r26
102:      b0 95             com      r27
104:      28 17             cp      r18, r24                // compare the four bytes
106:      39 07             cpc      r19, r25
108:      4a 07             cpc      r20, r26
10a:      5b 07             cpc      r21, r27
10c:      41 f4             brne      .+16           ; 0x11e <loop+0x60>  //branch if not equal




CasNet

If curdata is defined as a signed integer then the the ">>" operator may be doing sign extension so that the MSB in 0xAAAA5555 is being shifted right to be 0xFFFFAAAA.

Regards,
David

Go Up