if (x & VK_SHIFT) { // Shift key pressed
...
dwExStyle= WS_EX_TOOLWINDOW OR WS_EX_TOPMOST
...
if (window.event.button & 1) { // left mouse button pressed...
...
if ((window.event.button & 3) == 3) { // left and right mouse button pressed...
...
if ((window.event.button & 3) != 0 ) { // either left OR right button pressed...
...
treeView1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Bottom;
... and wondered what is going on. In this article, I hope to enlighten you, or at least pass on enough information to make you dangerous :-)
<INPUT TYPE=checkbox CHECKED ID=chk1> ...etc...
To indicate one of the two possible options (checked or not checked) we blithely use 16 bytes of UNICODE text to spell out the entire word " CHECKED". That is 256 bits where (using some hypothetical more efficient format) you could get by with a single bit. XML is also unbelievably inefficient as a data transfer mechanism, but let's not go there. I'm not here to malign HTML or XML, I'm just illustrating a "state of mind" that is common these days. It seems to me that when there's an opportunity for a hundredfold increase in efficiency, it's something you ought to explore.
1010 is 8+2 = 10 (A in hex)
0010 is 2 (2 in hex)
10100010 is A2 in hex.
Now after reading that, you can take any numeric value and turn it into a set of 1s and 0s.
z= x AND y (Visual Basic)
z= x & y (most other languages)
10001000
AND 00001111
00001000 (result contains a 1 only where both operands have a 1)
OR
z= x OR y (Visual Basic)
z= x | y (most other languages)
10001000
OR 00001111
10001111 (result contains the 1s from both operands)
NOT
z= NOT x (Visual Basic)
z= ~ x (most other languages)
NOT 10000111
01111000 (result contains a toggling of all of the bits; 1->0, 0->1)
10101001 (the starting value)
AND 00001111 (the mask, low four bits set to 1)
00001001 (result contains only data from the lower four bits)
if ( (dwFlags & 4 ) == 4 ) {
... the third lowest bit is set
}
if ( (dwFlags & 4) == 0 ) {
... the third lowest bit is clear (not set)
}
//---------------------------- bit flags for dwCarOptFlags
#define COF_None 0x0000
#define COF_Hatchback 0x0001
#define COF_SunRoof 0x0002
#define COF_FourDoor 0x0004
#define COF_AmRadio 0x0008
#define COF_8TrackTape 0x0010
...
if ( rCar.dwCarOptFlags & COF_AmRadio ) {
... the car has a radio
}
int nSearchMask= (COF_SunRoof | COF_AmRadio);
if ( (rCar.dwCarOptFlags & nSearchMask) == nSearchMask ) {
... the car has BOTH a radio and a sun roof
}
You can see if a car has neither option with this statement:
if ( (rCar.dwCarOptFlags & nSearchMask) == 0 ) {
... the car has NEITHER a radio NOR a sun roof
}
You can see if a car has either option with this statement:
if ( (rCar.dwCarOptFlags & nSearchMask) != 0 ) {
... the car has EITHER a radio OR a sun roof or both
}
Note that when using multiple-bit masks, it's usually important to do the AND, and then compare the result to the mask value. You will often see, for instance:
if ( rCar.dwCarOptFlags & nSearchMask ) { // valid, but avoid this syntax
... the car has EITHER a radio OR a sun roof or both
}
...but that is a shorthand/idiom for the real question being asked, which is:
if ( (rCar.dwCarOptFlags & nSearchMask) != 0) { // preferred syntax
... the car has EITHER a radio OR a sun roof or both
}
That's because an if statement evaluates its single operand and branches based on whether that value is non-zero. In the case of a binary AND operation, the result is non-zero when any of the mask bits are set in the result. It's best to ask the question specifically, adding the (... != 0) if that's what you need to know.
SELECT * FROM Cars WHERE (CarOptFlags & 3)=3;
If CarOptFlags is an indexed field, that will be a very fast query.
rCar.dwCarOptFlags= COF_None; // no options
rCar.dwCarOptFlags= COF_SunRoof | COF_AmRadio; // two options
The harder task is to set a single flag without altering the other ones. Here's the sequence:
rCar.dwCarOptFlags= rCar.dwCarOptFlags OR COF_AmRadio // VB
rCar.dwCarOptFlags= rCar.dwCarOptFlags | COF_AmRadio; // C
rCar.dwCarOptFlags |= COF_AmRadio; // C |= operator idiom
' COF_AmRadio is 00001000
'VB:
nNoRadioMask = NOT COF_AmRadio ' 11110111
rCar.dwCarOptFlags= rCar.dwCarOptFlags AND nNoRadioMask
// C/C++/C#, et al.:
int nNoRadioMask= ~COF_AmRadio; // 11110111
rCar.dwCarOptFlags &= nNoRadioMask;
DWORD ModifyCarOptFlags( CarRec& rCar, DWORD dwAdd, DWORD dwRemove )
{
DWORD nFlags= rCar.dwCarOptFlags;
nFlags &= ~dwRemove;
nFlags |= dwAdd;
rCar.dwCarOptFlags= nFlags;
return( nFlags );
}
If you are working in an object-oriented programming language (and who isn't?) then you can provide easy-access functions to turn on or off any of the bits...
class CCarRec
{
bool CCarRec::get_HasSunRoof() { return (dwCarOptFlags & COF_SunRoof) == COF_SunRoof); };
void CCarRec::set_HasSunRoof() { dwCarOptFlags |= COF_SunRoof; };
...
}
Another thing I've done with bit flags is create a "toString" function like this:
CString CCarRec::OptsAsString()
{
CString sRet="";
if ( dwCarOptFlags & COF_Hatchback) sRet += "Hatchback ";
if ( dwCarOptFlags & COF_SunRoof ) sRet += "SunRoof ";
if ( dwCarOptFlags & COF_FourDoor ) sRet += "FourDoor ";
if ( dwCarOptFlags & COF_AmRadio ) sRet += "AmRadio ";
... etc...
return sRet;
}
The idea is that even if the future code maintainer hasn't read this article, he can still do a string search or an eyeball-check to know what option flags are set.
#define COF_Hatchback 0x0001
#define COF_SunRoof 0x0002
#define COF_FourDoor 0x0004
//#define COF_AmRadio 0x0008
#define COF_AmFmRadio 0x0008 // redefined 1977 [LLR]
#define COF_8TrackTape 0x0010
...
#define COF_CassetPlyr 0x0080 // added 1977 [LLR]
#define CTF_IsDiesel 0x0100 // added 1979 [LLR]
...
#define COF_CDPlyr 0x1000 // added 1989 [LLR]
...
#define CTF_IsHybrid 0x04000000 // added 2006 [JM]
#define CTF_HasBluetooth 0x08000000 // added 2009 [DR]
From the comments, I could see that the flags variable had started out as a 16-bit word, then evolved into a 32-bit value over time (it was still defined as an unsigned int). The point is that the same field started out containing information on just a handful of options, and over the course of many years, now identifies 28 different things -- and there is room for four more -- all without changing the database schema.
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (3)
Commented:
I wonder if you'd consider writing some assembly for beginners articles. I, for one, would very much like to get my hands on such material. There is precious little on the web aimed at the absolutely noob like myself.
I know this is a specialist area for you so I thought I might be able to encourage you to push the ol' Rollin's magic pen in that direction :)
Best regards,
evilrix
PS. Very nice article Dan. Get's my "yes" vote above.
Commented:
"Oh, I get it,... It's one of those see plus plus things..."
:)
Commented:
Voted yes above.