Contents
Once I was roaming the Visual C++ forum (again), I had to face the fact that bitwise operations, and binary in general, are rarely in beginner's common sense. After having pained my fingers to write a very long answer to that innocent person, it became obvious that I had to share this obfuscated knowledge with the community through this article.
This is obviously a beginners article, but if you want to get deeper knowledge about the C/C++ bitwise operators cover, you can read the very complete article, An introduction to bitwise operators by PJ Arends. You can also go into a very complex (but effective) analysis of bit hacking with the article, Bit Twiddling Hacks By Sean Eron Anderson.
I'm going to present in the most complete way that I can about what we can do with bitwise operators, flags and all that binary stuff.
One of the places where we most find the use for this is certainly when a library provides a set of enumerations and when functions use DWORD as a flags container. Let's take for that article the example of an enum which defines some styles:
enum {
STYLE1 = 1,
STYLE2 = 2,
STYLE3 = 4,
STYLE4 = 8,
STYLE5 = 16,
STYLE6 = 32,
STYLE7 = 64,
STYLE8 = 128
};
|
OR |
enum {
STYLE1 = 0x1,
STYLE2 = 0x2,
STYLE3 = 0x4,
STYLE4 = 0x8,
STYLE5 = 0x10,
STYLE6 = 0x20,
STYLE7 = 0x40,
STYLE8 = 0x80
};
|
As we can see, these constants are all powers of 2. To understand why these constants are chosen, we must go in binary representation:
1 -> 0b 00000000 00000000 00000000 00000001
2 -> 0b 00000000 00000000 00000000 00000010
4 -> 0b 00000000 00000000 00000000 00000100
8 -> 0b 00000000 00000000 00000000 00001000
16 -> 0b 00000000 00000000 00000000 00010000
32 -> 0b 00000000 00000000 00000000 00100000
64 -> 0b 00000000 00000000 00000000 01000000
128 -> 0b 00000000 00000000 00000000 10000000
Notice that for all of these values, only one bit is set at a time, all the others are equal to 0. You now can see a high level of interest appearing in this, which is that each bit is used as a flag for a functionality (here, each bit represents a style). We can now imagine a way to mix the flags together in one variable, to avoid using as many booleans as we need flags. Consider the following example :
0b 00000000 00000000 00000000 00100101
Flags of Style1, Style3 and Style6 are set
We face a problem now. C++ doesn't handle binary directly. We have to use bitwise operators instead. There are 3 atomic bitwise operators to know, presented by ascending order of priority : OR (|), AND (&) and NOT (~). Here are their behaviors:
x y | x y & x ~
--------- --------- -------
0 0 0 0 0 0 0 1
0 1 1 0 1 0 1 0
1 0 1 1 0 0
1 1 1 1 1 1
Knowing this, we can use these operators to build some mixes such as the ones presented above.
In the case of the instruction STYLE1 | STYLE3 | STYLE6, we OR the constants like this:
0b 00000000 00000000 00000000 00000001 <- STYLE1
0b 00000000 00000000 00000000 00000100 <- STYLE3
0b 00000000 00000000 00000000 00100000 <- STYLE6
-----------------------------------------------
0b 00000000 00000000 00000000 00100101 <- STYLE1 | STYLE3 | STYLE6
We can see that the bitwise OR operator is pretty much like the addition (+) operator. However, you have to be very careful if you wished to use + instead or |. The reason is simple: adding 1 + 1 resolves into 0 (plus one carry over 1). You won't see any problem if all the constants are strictly different though, but I won't go deeper as it is a bad practice to use other than bitwise operators when processing binary operations.
Commonly, such mixes stick to the DWORD type. However, this is not a must as we can do this with any integer types (char, short, int, long...). A DWORD is an unsigned 32 bits integer (like those used in the binary representations of this article). Let's imagine the case when we have such a DWORD constructed in a function, and passed to another in parameter. How can the called function know which bits are set, and which are not? Easy... Follow me!
Say we want to know if the bit of STYLE8 is set in the DWORD passed in parameter. We must have a mask which we will call the AND parameter. In practice, the mask is the same as the constant we are about to test, so there's no additional code to create such a mask:
DWORD parameter -> 0b 00000000 00000000 00000000 00100101
STYLE8 mask -> 0b 00000000 00000000 00000000 10000000
----------------------------------------
Bitwise AND -> 0b 00000000 00000000 00000000 00000000 <- 0x00000000
DWORD parameter -> 0b 00000000 00000000 00000000 10100101
STYLE8 mask -> 0b 00000000 00000000 00000000 10000000
----------------------------------------
Bitwise AND -> 0b 00000000 00000000 00000000 10000000 <- STYLE8
If the AND operation returns 0, then, the bits were not set, otherwise, you get the mask you applied.
OK, now, in practice, here is how you'll often see it:
void SetStyles(DWORD dwStyles) {
if ((STYLE1 & dwStyles) == STYLE1) {
}
else if ((STYLE2 & dwStyles) == STYLE2) {
}
else if ((STYLE3 & dwStyles) == STYLE3) {
}
}
I didn't present the third operator NOT (~) yet. It is generally used when you have a set of bits, in which some are set and some aren't, and where you'd like to remove one of them. The sample of code below exposes how this can be done:
void RemoveStyle5 (DWORD& dwStyles) {
if ((STYLE5 & dwStyles) == STYLE5) {
dwStyles = dwStyles & ~STYLE5;
}
}
I didn't mention the XOR ( ^ ) operator yet. The reason why it comes last is for the only reason that this operator is not atomic; that means that we can reproduce its behavior with the other operators presented already:
#define XOR(a,b) (((a) & ~(b)) | ((b) & ~(a)))
Anyway, this operator can be used to easily switch one bit :
void SwitchStyle5 (DWORD& dwStyles) {
dwStyles = dwStyles ^ STYLE5;
}
Now, to perfect your sharpen skills on bits handling, there are few other operators you have to know to be unbeatable: the shift operators. Those can be recognized like this : << (left shifting, follow the arrows), >> (guess what, this is a right shifting).
What a shifting operator is moving the bits of n positions to the right or to the left. The "space" made by the movement is padded with zeros, and the bits pushed over the limit of the memory area are lost.
Let's take an example:
BYTE dwStyle = STYLE1 | STYLE3 | STYLE6;
<-
dwStyle = dwStyle << 3;
BYTE dwStyle = STYLE1 | STYLE3 | STYLE6;
->
dwStyle = dwStyle >> 3;
"But" I hear you say, "what is that for" ?". Well, there are tons of applications which I don't particularly have in mind right now, but trust me, when you need it, be happy it's there.
Anyway, two funny uses of such operators I can think of is the division and the multiplication of an integer by 2. Check this:
char i = 127;
i = i >> 1;
i = i << 1;
Shifting one bit right, then one bit left gives a different result from the beginning. That's because as we just saw, the "overflown" bits are lost, and the newly inserted ones are set to 0. But let's look closer. This is working anyway because we are working on integers. That is, dividing an odd number will not give a float (we don't care about the remaining 0.5).
Here, 127 / 2 should be 63.5, so it gives 63, due to the truncation.
63 * 2 = 126, isn't it what we want ?! :-)
Now we've seen all the useful operators, just know that all of them have their own assignment operator.
dwStyle &= 0x2 --> dwStyle = dwStyle & 0x2
dwStyle |= 0x2 --> dwStyle = dwStyle | 0x2
dwStyle ^= 0x2 --> dwStyle = dwStyle ^ 0x2
dwStyle <<= 0x2 --> dwStyle = dwStyle << 0x2
dwStyle >>= 0x2 --> dwStyle = dwStyle >> 0x2
Thanks to Randor in the VC++ forum, here is a nice example of what is possible to do with such operators (Credit for the discovery of this little neat trick below goes to Sean Anderson at stanford university).
"How is it possible to reverse the bits of an integer, say from 11010001 to 10001011 ?"
BYTE b = 139;
b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
"Wowwww, how is this working man ?!"
DWORD iTmp = 0;
BYTE b = 139;
DWORD c = (b * 0x0802LU);
c &= 0x22110LU;
DWORD d = (b * 0x8020LU);
d &= 0x88440LU;
iTmp = (c | d);
iTmp = iTmp * 0x10101LU;
iTmp >>= 16;
b = iTmp;
Well, here we are then. If you came here to understand these binary operations, I hope that I helped you in your way. If you came to see what was going on here, then don't hesitate to point my mistakes if any, so that I can fix them.
The following links are for complimentary knowledge, if you like to go deeper in bitwise handling:
| You must Sign In to use this message board. |
|
|
 |
|
 |
After looking online, I found a way to pack a date using 16 bits. However, it only works for years 0..99:
unsigned short packeddate; unsigned int year, mon, mday;
packeddate = mon << 0x0c | mday << 0x07 | year;
Is there a way to pack dates using 32 bits so that the year can be represented using 4 digits?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
all depends how many bits you want to reserve for each "part" of the date.
Day part: A month can have 31 days max, so the day part can have values from 0 up to 30. 30 in binary is represented as 0b11110, so 5 bits.
Month Part: A year has 12 months, so the month part can store values from 0 up to 11. 11 in binary is represented as 0b1011, so, 4 more bits.
Year Part: here, all depends how many possible values you want to store there. that will change necessarily the number of bits required. until now, we've used 9 bits for the day + month parts. Obviously, I cannot stand in a byte (a byte is 8 bits), so we have to use 2 bytes minimum. If we choose so, we have 16-9=7 bits remaining for the year, which mean up to 128 values. This is OK if you store the year on 2 digits (what you're doing currently), or if you say for example 0b0000000 is 1900, and then 2008 is 0b1101100 (you choose your own meaning). if you want to use much choices for the dates, you need more bits, and you have to start using another byte). If we start using 3 bytes for such a structure, the date would use (3*8)-9=15 bits remaining for the year, which is up to 32768 values ! I could suggest then to reserve a bit for the sign of the year (if you need so). with this the year would be stored on 15 bits : 1 bit for the sign, and 14 for the year. And 14 bits lets up to 16384 values.
here is how to code this easily :
struct MyPackedDate { unsigned int day : 5; unsigned int month : 4; unsigned int year_sign : 1; unsigned int year_value : 14; };
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for the article! I stumbled upon it in your sig, and now that I know the possibility exists, it is going to do wonders for network programming!
One thing though, in your article you say that
1 -> 0b 00000000 00000000 00000000 00000001 2 -> 0b 00000000 00000000 00000000 00000010 4 -> 0b 00000000 00000000 00000000 00000100 8 -> 0b 00000000 00000000 00000000 00001000 16 -> 0b 00000000 00000000 00000000 00010000 32 -> 0b 00000000 00000000 00000000 00100000 64 -> 0b 00000000 00000000 00000000 01000000 128 -> 0b 00000000 00000000 00000000 10000000
I would like to know, is it possible to use the other 24 Bits (I am assuming so) and if yes, how? Do you simply continue on with more base 2 numbers (2^n), i.e. 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, etc, or would that simply produce something like 10000001 (I have no idea what that comes out as)
Also, that draws another matter to my attention, those 8 numbers should cover the next 8 bits / the next byte, however a 16 bit int can only hold up to 65535, which is actually 17 bits according to my calculations, however I put 2^16 into my calculator and I get 65536, which is correct...
it makes my head hurt...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Sauce! wrote: is it possible to use the other 24 Bits ?
of course, I was simply showing an example with the 8 lower bits, but thanksfully every 32 bits in a DWORD can be set (or it is useless to have 32 bits then).
Sauce! wrote: how?
DWORD dw = 0x40200080; this produces the following binary for the variable dw :
0b 01000000 00100000 00000000 10000000
Sauce! wrote: Also, that draws another matter to my attention, those 8 numbers should cover the next 8 bits / the next byte, however a 16 bit int can only hold up to 65535, which is actually 17 bits according to my calculations, however I put 2^16 into my calculator and I get 65536, which is correct...
don't make the mistake...
0 is a value. so, from 0 to 65535, that gives you actually 65536 values...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
toxcct wrote: DWORD dw = 0x40200080;
this produces the following binary for the variable dw :
0b 01000000 00100000 00000000 10000000
I don't think I am quite following you here. Is there some kind of simple conversion involved or is it something quite cryptic?
toxcct wrote: 0 is a value. so, from 0 to 65535, that gives you actually 65536 values...
There you go, I knew it was something silly like that! :P
Thanks again, This is going to prove very useful indeed.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
C/C++ don't allow to type binary values directly into your variables. however, hexadecimal is supported.
if you don't understand my first comment to you answer, then you probably need first to learn how to convert from bin to hexa (and vice versa)...
Sauce! wrote: There you go, I knew it was something silly like that
hehehe... same happens with arrays... when you declare an array being an int[10] for instance, you access the cells through indexes from 0 to 9...
Sauce! wrote: Thanks again, This is going to prove very useful indeed.
You're welcome
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
toxcct wrote: if you don't understand my first comment to you answer, then you probably need first to learn how to convert from bin to hexa (and vice versa)...
Sorry, I didn't realise that was hexadecimal there, my mind begins to go blank when it gets late.
I know how to convert from decimal to binary, thanks to an electronics book (not as strange a place as you may think), and I did a quick google for converting Hex to Binary, which seems pretty simple - a single hexadecimal can be represented by a nibble, or 4 bits?
If that is correct then i'm all good. Thanks for a great article / mini tutorial thing.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
that's it, an hexadecimal digit is a representation of 4 bits.
Sauce! wrote: Thanks for a great article / mini tutorial thing
that's all it was done for 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am working with a struct MONTHLYDATE defined in mstask.h. It uses an DWORD enum exactly like what is presented in this article to represent each day of the month:
Day--Val (Hex)----Val (Bin)------------------------Val (Int) 1 - 0x00000001 - 00000000 00000000 00000000 00000001 - 1 2 - 0x00000002 - 00000000 00000000 00000000 00000010 - 2 3 - 0x00000004 - 00000000 00000000 00000000 00000100 - 4 4 - 0x00000008 - 00000000 00000000 00000000 00001000 - 8 5 - 0x00000010 - 00000000 00000000 00000000 00010000 - 16 6 - 0x00000020 - 00000000 00000000 00000000 00100000 - 32 .... 31 -0x40000000 - 01000000 00000000 00000000 00000000 - 1073741824 My problem is this - Knowing what the val is, I want to print the corresponding day (I know it will only represent one day) withouth having to do a huge if statement. I figured out that if you use the value you can do the following math:
Value = 2^(Day -1)
which I can turn around to get (taking into consideration that I couldn't find a log base 2 function:
Day = (log(value)/log(2)) + 1
But this seems very inelegant... is there a better way???
Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
if (and only if) only one bit is set (as it should be) you can do:
int getDay(DWORD dwValue) { for (i=0; i<32; i++) { if (dwValue & 1) return (i+1); dwValue >>= 1; } return 0; }
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
Can you *please* explain what is "Managed" by your term mr arkitech? For your skill I think you should be deserving a place in the .net archKitects team. Good Luck. But dont ever piss off like this again. .
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
you're stupid kid.
voting my two articles down because i had notified you softly that you had submited the same article[^] twice...
now, you're telling me that my article belongs to the Managed C++ section ?! Crap, do you even know what Managed code is ? looking at your profile[^], i don't even believe you really know what C++ is actually. so, thank you very much for having voted VisualCalc down, which was far from being in relation with the original post.
|
| Sign In·View Thread·PermaLink | 4.60/5 |
|
|
|
 |
|
|
 |
|
 |
ArkitechEBC wrote: I'm simply trying to say to you that if you're using C++ to do this. Then you are probably doing it wrong and there is a better .NET 'managed' way to do it.
pfff, what a crap. that's obvious you don't know anything to C/C++.
i was providing here a tutorial for beginners (as you can spot on the article banner) for using enum flags.
i don't bother there are different/better/worst ways to do that in C#, i am presenting the C/C++ solution !!!
|
| Sign In·View Thread·PermaLink | 4.60/5 |
|
|
|
 |
|
 |
Tox I think you need to just ignore him. He seems to belong to the "Extreme dumb" group.
BTW Nice article. Got my 5.
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
|
 |
|
 |
Also take a look at the Bit Twiddling Hacks[^] by Sean Eron Anderson.
For example: - Counting bits set - Computing parity - Reversing bit sequences - Round up to the next highest power of 2
and other nice things.
|
| Sign In·View Thread·PermaLink | 3.40/5 |
|
|
|
 |
|
 |
this article was not an exhaustive presentation of all the possible ways of doing things. once again, i repeat that i designed this essay for beginners, so i didn't way to confuse them with strange obfuscated optimized code.
by the way, the link is good and i'm going to add it to the article.
thanks.
TOXCCT >>> GEII power [toxcct][VisualCalc 2.24][3.0 soon...]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
...erm.. first watch out for
DWORD a=1; XOR(++a,a++); ...
Also, if "atomic" means can't be defined from the other operators, then XOR can be defined from NOT and OR But, OR can be defined from NOT and AND...think about it....
Frances
|
| Sign In·View Thread·PermaLink | 2.33/5 |
|
|
|
 |
|
 |
Buontempo wrote: DWORD a=1; XOR(++a,a++);
i see no problem in my XOR definition with that.
however, i can warn you about one thing : don't use such pre/post increments/decrements one the same variable in the same expression, this will result in unexpected results when you change of compiler. this is a very bad habit, and lowers the level of my article, which major audience is especially beginners.
Buontempo wrote: Also, if "atomic" means can't be defined from the other operators, then XOR can be defined from NOT and OR But, OR can be defined from NOT and AND...think about it....
i don't understand you here. so what did you mean ?
TOXCCT >>> GEII power [toxcct][VisualCalc 2.24][3.0 soon...]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
toxcct wrote: Buontempo wrote: DWORD a=1; XOR(++a,a++);
>>"i see no problem in my XOR definition with that.
however, i can warn you about one thing : don't use such pre/post increments/decrements one the same variable in the same expression, this will result in unexpected results when you change of compiler. this is a very bad habit, and lowers the level of my article, which major audience is especially beginners."
OK, However you said "flags in C++"...the usual idiom in C++ is to use an inline function. Consider
#define XOR(a,b) (((a) & ~(b)) | ((b) & ~(a)))
versus
inline DWORD xor(DWORD a,DWORD b) { return (((a) & ~(b)) | ((b) & ~(a))); }
The latter avoids the problems with using the pre/post increment operators (and other gotchas) in macros. Your macro works, provided certain inputs aren't used, as you say, but those would be safe in the inline version. Perhaps this is a style point...I'm not saying your code is wrong it's just more C than C++. C would use a macro so the code gets put inline, without the overhead of a function call...inline requests the compiler try to do the same.
toxcct wrote: Buontempo wrote: Also, if "atomic" means can't be defined from the other operators, then XOR can be defined from NOT and OR But, OR can be defined from NOT and AND...think about it....
"i don't understand you here. so what did you mean ?"
You said 'atomic' meant could be formed from the other logical operators. My understanding is that you don't need all the operators...See http://en.wikipedia.org/wiki/Logical_operator. Depending on which operators you start with you will probably be able to form the others.
For example, You could get OR(|) from AND(&) and NOT(~) (x OR y) is the same as (NOT(NOT x AND NOT Y))
x y ~(~x & ~y) --------------- 0 0 0 1 0 1 1 0 1 0 1 0 1 1 1 0
so you could claim the OR isn't atomic. Mind you, you can also form AND using just NOT and OR...and so on.
Fun can be had trying to form each of the logical operators from one or more of the others....as an aiding to understanding rather than writing better code of course.
........................ Overall though, sorry if I came across as rude. Your explanation is clear from the response you have had...I just wanted to point out these two things.
Frances.
...check out http://accu.org/ if you want to get good at C/C++/Java/C# coding...
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Everything can be synthesized from the NAND operator; all but one of the dyadic (two-operand) operators may be synthesized from four or fewer NANDs. XNOR requires five.
The NOR operator may be substituted for NAND. When using NOR, XNOR takes four NORs and XOR takes five.
A couple alternatives which I've not seen used much in electronics would be (A and not B), or else (A or not B). I'm surprised I haven't seen 7400-series chips to implement those; they are seldom optimal, but are often better than NANDs.
Function/NANDs/NORs/(A and not B) (A or not B) AND/2/3/2/3 OR/3/2/3/2 NAND/1/4/3/2 NOR/4/1/2/3 A~B/3/2/1/2 A+~B/2/3/2/1 XOR/4/5/3/4 XNOR/5/4/4/3
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Is there a mathematical formula to count the number of flags selected in an enumeration value? Using your example, let’s say I want to create an array with X elements to store the number of styles selected in the enumeration. If the enumeration value is 13, that is 1+4+8=13. In your example 1, 4 and 8 represent Style1, Style3 and Style4. So I need an array with 3 elements to store the three styles. Is there a formula that would result 13 to equal 3?
So this flag count formula would result in
enum, flag count 1 1 2 1 3 2 4 1 5 2 6 2 7 2 8 1 9 2 10 2 11 2 12 2 13 3 14 3 ...
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|