Easier bitwise Operations






4.46/5 (10 votes)
A collection of templates that simplify the comprehension of bitwise operations
Introduction
I've been developing software using C/C++ for a very long time yet I still have to think twice when I encounter bitwise operations, let alone when I have to explain them to somebody else! For example:
unsigned const STAT_ONE = 0x0001;
unsigned const STAT_TWO = 0x0002;
unsigned status = 0x0001;
if(status & (STAT_ONE | STAT_TWO)) // Does this evaluate to true or false?
DoSomething();
We all know that the preceding statement checks if both STAT_ONE
and STAT_TWO
bits are set then DoSomething()
will be executed... or is it if either STAT_ONE
or STAT_TWO
bits are set? Let's see:
0001 or // STAT_ONE
0010 // STAT_TWO
----
0011 and // STAT_ONE | STAT_TWO
0001 // status
----
0001 // status & (STAT_ONE | STAT_TWO)
Because the result is non-zero, then DoSomething()
will be executed. I think this can be very tricky, especially if the expressions get too complex. Isn't the intent of the following code easier to understand and less error-prone?
unsigned const STAT_ONE = 0x0001;
unsigned const STAT_TWO = 0x0002;
unsigned status = 0x0001;
if(isAnyBitSet(status, STAT_ONE | STAT_TWO)) // This evaluates to true, bit
// STAT_ONE is set and bit STAT_TWO
// isn't. Same as previous example
DoSomething();
if(areAllBitsSet(status, STAT_ONE | STAT_TWO)) // This evaluates to false,
// bit STAT_ONE is set but bit
// STAT_TWO isn't
DoSomething();
Also it's very convenient to access a bit's value by its position like this:
if(isBitSetByPos(status, 5))
bitClearByPos(status, 5);
All the functions provided in the BitTools.h header are inlined so there is no size or run-time speed tradeoffs to worry about.
Templates
Bitmask-based Functions
-
template <class T, class U> bool isAnyBitSet(T value, U mask)
Returns
true
if any of the bits inmask
is set invalue
. Defined as:(value & mask) != 0
1010 and // value 0110 // mask ---- 0010 // Non-zero: true
-
template <class T, class U> bool areAllBitsSet(T value, U mask)
Returns
true
if all the bits inmask
are set invalue
. Defined as:(value & mask) == mask
1010 and // value 1110 // mask ---- 1010 // 1010 == 1010: true
-
template <class T, class U>
bool areAllBitsClear(T value, U mask)
- Returns
true
if all the bits inmask
are cleared invalue
. Defined as:(value & mask) == 0
1010 and // value 0101 // mask ---- 0000 // Zero: true
-
template <class T, class U> T setBits(T value, U mask)
Returns
value
with themask
bits set. Defined as:value | mask
1000 or // value 0110 // mask ---- 1110
-
template <class T, class U> T setBitsExcept(T value, U mask)
Returns
value
with all the bits set except themask
bits. Defined as:value | ~mask
1001 not // mask ---- 0110 or // ~mask 0001 // value ---- 0111
-
template <class T, class U> T clearBits(T value, U mask)
Returns
value
with themask
bits cleared. Defined as:value & ~mask
1001 not // mask ---- 0110 and // ~mask 1111 // value ---- 0110
-
template <class T, class U> T clearBitsExcept(T value, U mask)
Returns
value
with all the bits cleared except themask
bits. Defined as:value & mask
0010 and // value 0110 // mask ---- 0010
-
template <class T, class U> T setClearBits(T value, U add, U remove)
Returns
value
with theadd
bits set and theremove
bits cleared. Defined as:(value | add) & ~remove
1101 or // value 0101 // add ---- 0111 0001 not // remove ---- 1110 and // ~remove 0111 // value | add ---- 0110
-
template <class T, class U, class V> T setBits(T value, U mask, V set)
Returns
value
with themask
bits set or cleared depending on the value ofset
.
Position-based Functions
-
template <class T> T setBitByPos(T value, unsigned char n)
Returns
value
with then
th bit set. Defined asvalue | (1 << n)
-
template <class T> T clearBitByPos(T value, unsigned char n)
Returns
value
with then
th bit cleared. Defined asvalue & ~(1 << n)
-
template <class T> bool isBitSetByPos(T value, unsigned char n)
Returns
true
ifvalue
has then
th bit set. Defined as(value & (1 << n)) != 0
-
template <class T> bool isBitClearByPos(T value, unsigned char n)
Returns
true
ifvalue
has then
th bit cleared. Defined as(value & (1 << n)) == 0
Conclusion
The templates contained in BitTools.h provide an easier and less error-prone way of expressing bitwise operations with no performance or size penalties compared to hand written code. I hope you find these functions as useful and easy to use as I did.