Off-Topic Discussion > Programming
Tricky Bools!
(1/1)
z64555:
We've been doing a bit of maintenance with the flags system in FSO, and something interesting came up that made me stop and think.
Specifically, this:
--- Code: ---#define VM_PADLOCK_UP (1 << 7)
#define VM_PADLOCK_REAR (1 << 8)
#define VM_PADLOCK_LEFT (1 << 9)
#define VM_PADLOCK_RIGHT (1 << 10)
#define VM_PADLOCK_ANY (VM_PADLOCK_UP|VM_PADLOCK_REAR|VM_PADLOCK_LEFT|VM_PADLOCK_RIGHT)
int Viewer_mode;
// Version A
if (Viewer_mode & ~VM_PADLOCK_ANY) {}
// Version B
if (~Viewer_mode & VM_PADLOCK_ANY) {}
--- End code ---
Note versions A and B, which differ only by the location of operator~, which is the bitwise NOT operator (makes all 0's into 1's and 1's into 0's). When placed in an if{} statement, C and C++ regards a non-boolean value (ints, floats, etc.) as TRUE if any bits in the value are 1's (that is, if the value is nonzero, it is TRUE). This little quirk will make things difficult for us as you'll soon see.
--- Code: ---// Version A
LHS RHS
00 & ~00 -> 00 & 11 -> 00 -> FALSE // A right-hand operand of 00 makes no sense for flag checking, so we don't use it
01 & ~00 -> 01 & 11 -> 01 -> TRUE
10 & ~00 -> 10 & 11 -> 10 -> TRUE
11 & ~00 -> 11 & 11 -> 11 -> TRUE
00 & ~01 -> 00 & 10 -> 00 -> FALSE
01 & ~01 -> 01 & 10 -> 00 -> FALSE
10 & ~01 -> 10 & 10 -> 10 -> TRUE
11 & ~01 -> 11 & 10 -> 10 -> TRUE
00 & ~10 -> 00 & 01 -> 00 -> FALSE
01 & ~10 -> 01 & 01 -> 01 -> TRUE
10 & ~10 -> 10 & 01 -> 00 -> FALSE
11 & ~10 -> 11 & 01 -> 01 -> TRUE
00 & ~11 -> 00 & 00 -> 00 -> FALSE
01 & ~11 -> 01 & 00 -> 00 -> FALSE
10 & ~11 -> 10 & 00 -> 00 -> FALSE
11 & ~11 -> 11 & 00 -> 00 -> FALSE
//Version B
LHS RHS
~00 & 00 -> 11 & 00 -> 00 -> FALSE
~01 & 00 -> 10 & 00 -> 00 -> FALSE
~10 & 00 -> 01 & 00 -> 00 -> FALSE
~11 & 00 -> 00 & 00 -> 00 -> FALSE
~00 & 01 -> 11 & 01 -> 01 -> TRUE
~01 & 01 -> 10 & 01 -> 00 -> FALSE
~10 & 01 -> 01 & 01 -> 01 -> TRUE
~11 & 01 -> 00 & 01 -> 00 -> FALSE
~00 & 10 -> 11 & 10 -> 10 -> TRUE
~01 & 10 -> 10 & 10 -> 10 -> TRUE
~10 & 10 -> 01 & 10 -> 00 -> FALSE
~11 & 10 -> 00 & 10 -> 00 -> FALSE
~00 & 11 -> 11 & 11 -> 11 -> TRUE
~01 & 11 -> 10 & 11 -> 10 -> TRUE
~10 & 11 -> 01 & 11 -> 01 -> TRUE
~11 & 11 -> 00 & 11 -> 00 -> FALSE
--- End code ---
As you can see from the snippet, the two versions are not the same.
Version A seems to check if any of the flags that are 0's in the RHS operand are 1's in the LHS.
Version B seems to check if any flags that are 1's in the RHS operand are 0's in the LHS.
Let's toss in another bit to see if these general rules hold up:
--- Code: ---// Version A
000 & ~001 -> 000 & 110 -> 000 -> FALSE
001 & ~001 -> 001 & 110 -> 000 -> FALSE
010 & ~001 -> 010 & 110 -> 010 -> TRUE
011 & ~001 -> 011 & 110 -> 010 -> TRUE
100 & ~001 -> 100 & 110 -> 100 -> TRUE
101 & ~001 -> 101 & 110 -> 100 -> TRUE
110 & ~001 -> 110 & 110 -> 110 -> TRUE
111 & ~001 -> 111 & 110 -> 110 -> TRUE
000 & ~010 -> 000 & 101 -> 000 -> FALSE
001 & ~010 -> 001 & 101 -> 001 -> TRUE
010 & ~010 -> 010 & 101 -> 000 -> FALSE
011 & ~010 -> 011 & 101 -> 001 -> TRUE
100 & ~010 -> 100 & 101 -> 100 -> TRUE
101 & ~010 -> 101 & 101 -> 101 -> TRUE
110 & ~010 -> 110 & 101 -> 100 -> TRUE
111 & ~010 -> 111 & 101 -> 101 -> TRUE
000 & ~011 -> 000 & 100 -> 000 -> FALSE
001 & ~011 -> 001 & 100 -> 000 -> FALSE
010 & ~011 -> 010 & 100 -> 000 -> FALSE
011 & ~011 -> 011 & 100 -> 000 -> FALSE
100 & ~011 -> 100 & 100 -> 100 -> TRUE
101 & ~011 -> 101 & 100 -> 100 -> TRUE
110 & ~011 -> 110 & 100 -> 100 -> TRUE
111 & ~011 -> 111 & 100 -> 100 -> TRUE
000 & ~111 -> 000 & 000-> 000 -> FALSE
001 & ~111 -> 001 & 000-> 000 -> FALSE
010 & ~111 -> FALSE
011 & ~111 -> FALSE
100 & ~111 -> FALSE
101 & ~111 -> FALSE
110 & ~111 -> FALSE
111 & ~111 -> FALSE
//Version B
~000 & 001 -> 111 & 001 -> 001 -> TRUE
~001 & 001 -> 110 & 001 -> 000 -> FALSE
~010 & 001 -> 101 & 001 -> 001 -> TRUE
~011 & 001 -> 100 & 001 -> 000 -> FALSE
~100 & 001 -> 011 & 001 -> 001 -> TRUE
~101 & 001 -> 010 & 001 -> 000 -> FALSE
~110 & 001 -> 001 & 001 -> 001 -> TRUE
~111 & 001 -> 000 & 001 -> 000 -> FALSE
~000 & 010 -> 111 & 010 -> 010 -> TRUE
~001 & 010 -> 110 & 010 -> 010 -> TRUE
~010 & 010 -> 101 & 010 -> 000 -> FALSE
~011 & 010 -> 100 & 010 -> 000 -> FALSE
~100 & 010 -> 011 & 010 -> 010 -> TRUE
~101 & 010 -> 010 & 010 -> 010 -> TRUE
~110 & 010 -> 001 & 010 -> 000 -> FALSE
~111 & 010 -> 000 & 010 -> 000 -> FALSE
~000 & 011 -> 111 & 011 -> 011 -> TRUE
~001 & 011 -> 110 & 011 -> 010 -> TRUE
~010 & 011 -> 101 & 011 -> 001 -> TRUE
~011 & 011 -> 100 & 011 -> 000 -> FALSE
~100 & 011 -> 011 & 011 -> 011 -> TRUE
~101 & 011 -> 010 & 011 -> 010 -> TRUE
~110 & 011 -> 001 & 011 -> 001 -> TRUE
~111 & 011 -> 000 & 011 -> 000 -> FALSE
~100 & 111 -> 111 & 111 -> 111 -> TRUE
~001 & 111 -> 110 & 111 -> 110 -> TRUE
~010 & 111 -> 101 & 111 -> 101 -> TRUE
~011 & 111 -> 100 & 111 -> 100 -> TRUE
~100 & 111 -> 011 & 111 -> 011 -> TRUE
~101 & 111 -> 010 & 111 -> 010 -> TRUE
~110 & 111 -> 001 & 111 -> 001 -> TRUE
~111 & 111 -> 000 & 111 -> 000 -> FALSE
--- End code ---
Looks like our general rule seems to hold up. Version A makes less sense than version B, because usually when we do a check against flags, we're concerned about the ones that are set rather than the ones that are clear.
"But what if you wanted to check if all bits of the flag where set, or clear?"
--- Code: ---//Checks if all bits set
(Viewer_mode & VM_PADLOCK_ANY) == VM_PADLOCK_ANY;
// Checks if all bits clear
(Viewer_mode & VM_PADLOCK_ANY) == 0;
--- End code ---
z64555:
As MageKing17 on IRC pointed out, it's preferred to do
--- Code: ---!(Viewer_mode & VM_PADLOCK_ANY)
--- End code ---
when checking if a single bit is clear. This notation also seems to check if all bits are clear.
AdmiralRalwood:
--- Quote from: z64555 on August 17, 2016, 04:40:00 pm ---when checking if a single bit is clear.
--- End quote ---
what
I didn't say that
z64555:
--- Quote ---4:34:08 PM - z64555: checking if a bit is clear. probably will go with !(Viewer_mode & VM_CAMERA_LOCKED)
4:34:21 PM - MageKing17: yes, that's how you should check that
4:34:36 PM - MageKing17: put a "not" in front of a check if a bit is set
--- End quote ---
Well, that's how I interpreted that. :P
AdmiralRalwood:
yes, but the way you wrote it implied that I'd said you should do something else for multiple bits when your question just hadn't been about multiple bits
Navigation
[0] Message Index
Go to full version