Go Down

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

#### yerg2k

##### Jan 22, 2008, 03:36 amLast 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 amLast 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

#2
##### Jan 22, 2008, 04:03 pm
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

#3
##### Jan 22, 2008, 04:31 pm
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

#4
##### Jan 26, 2008, 12:25 am
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

Please enter a valid email to subscribe

To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy