 # Actionable bitwise with C++

I've seen a few posts here and there talking about bitwise operations. I enjoyed reading them, but a lot of the best ones (imo) didn't show great examples of bitwise usage. As someone who leverages bitwise operations everyday at my job, I figured I'd make a post to potentially offer some clarity on the subject by writing up a big example.

Before we get to examples of where we might use this stuff, lets look over the bitwise operations.

If you'd like to see executable code with all of this information, check it out here.

### AND

AND-ing two binary values will indicate when corresponding bits in the two inputs are '1' or in the 'on' position.

For example :

    00000101 & 00000011 = 00000001


Here is the same thing, but stacked to give an easier visual representation of what is going on:

    00000101
00000011
--------
00000001


### OR

OR-ing two binary values will yield a result that tells us if a bit in one input OR a bit in the other input is '1' or in the 'on' position.

For example :

    01001000 | 10111000 = 11111000


Here is the same thing, but stacked to give an easier visual representation of what is going on:

    01001000
10111000
--------
11111000


### XOR

XOR-ing is pretty cool. Similar to OR, but different in that it requires exclusivity in the input bits being in the '1' or 'on' position. Easily understood as "One or the other, but not both."

    11111111 ^ 00001111 = 11110000


Here is the same thing, but stacked to give an easier visual representation of what is going on:

    11111111
00001111
--------
11110000


### NEG

Negation! This can be understood as 'flipping' or 'toggling' the bits.

    ~11111010 = 00000101


Again, the stacked example:

    11111010
--------
00000101


### Shifting

The last thing we will look at before the big example is shifting. Shifting is neat. We basically just push the bits left or right within the binary number.

    0x01      = 00000001
0x01 << 1 = 00000010
0x01 << 2 = 00000100
0x01 << 3 = 00001000


Of course, we can also shift in the other direction!

10000000 >> 5 = 00000100


As you can see, by >> by '5' we've moved the bit 5 spaces to the right. Wicked!

## Time for some use-cases (examples)!

These are some cases where we might chose to use bitwise logic.

### MSB Checking

This one might seem strange, but there are cases where we might want to see if the far-left bit of a byte is in the 'on' position.


void someFunc() {

uint8_t var = 0x8A; // In binary, this is : 10001010

// If we want to see if the most significant bit is set
// we can right shift a few places and use it as a bool
// because 1's are true, and 0's are false.

bool isBitSet = var >> 7;

if( isBitSet ) {
// Of course, we COULD drop ' var >> 7 ' in as the conditional
// directly, but for the example I decided not to.

std::cout << "The bit is set!" << std::endl;
}

}



Lets say we have a 32-bit number that represents a color! We all like colors. Why 32-bit ? Because it can happen. Lets say our color happens to be encoded as-follows:

    Alpha = Byte One
Blue  = Byte Two
Green = Byte Three
Red   = Byte Four


Given the following 32-bit binary number, how can we extract these values?

    Alpha    Blue     Green    Red
10001100 11101001 00001010 00000011


    uint32_t alphaMask = 0xFF000000; // Mask to obtain alpha byte


Using these masks, we can leverage the functionality of AND to ensure that we get the value we want... and that is pretty great.

    //                     A B G R
uint32_t abgrColor = 0x8CE90A03;    // The actual 32-bit color

uint32_t alpha = abgrColor & alphaMask;
uint32_t blue  = abgrColor & blueMask;
uint32_t green = abgrColor & greenmask;
uint32_t red   = abgrColor & redMask;
}


To demonstrate one of these as we did above, lets take the binary representations of abgr and stack it on the blue mask.

10001100 11101001 00001010 00000011
00000000 11111111 00000000 00000000
-----------------------------------
00000000 11101001 00000000 00000000


Hooray! We've discovered that the byte representing our blue color is :

    11101001


### Chopping!

Lets say we have 32 bits ( a color maybe? ) and we want to send it somewhere. The specification for the protocol that we need to send it over demands we do it 8 bits at a time. Why? I don't know, I didn't write the spec.

In order to do this we need to chop the 32 bits up into 4 bytes and send them sequentially. Then, on the other side, we need to reconstruct the original data.

Its okay, we can do this.


uint32_t var = 0x8CE90A03;           // This is our color, but in hex

uint8_t pack;                     // A 'pack' of 4 bytes

// Using a mask (like above) we grab the data
pack = ( var  & 0x000000FF);
pack = ( var  & 0x0000FF00) >> 8;  // But when we mask some bits we
pack = ( var  & 0x00FF0000) >> 16; // need to move them into a range
pack = ( var  & 0xFF000000) >> 24; // that works within a byte


Explanation

If the masking and shifting seems confusing maybe this will help!
If you recall from the blue byte extraction above we ended up with the following data:

    Byte 1   Byte 2   Byte 3   Byte 4
00000000 11101001 00000000 00000000


However, uint8_t represents 1 byte. If we attempted to construct a uint8_t with that data, it would be 00000000 as only 'Byte 4' would be used. That means we need to get JUST the data in 'Byte 2' we have to right shift by 16.

      00000000 11101001 00000000 00000000 >> 16
-----------------------------------
00000000 00000000 00000000 11101001


Woot! Now that '11101001' is in the far right we can safely construct a uint8_t and preserve the 'blue' data.

/Explanation

Now that we have a pack of bytes representing our color data, lets just assume we called something to send it, and now we need to reconstruct it as a uint32_t on the receiver end.

This is relatively easy, but not necessarily straight forward.

uint32_t unpacked = pack | (pack << 8) | (pack << 16) | (pack << 24);


We're done!

But what did we do?

We undid all of the chopping of course! We took each byte, and placed them into their corresponding space within the new 32-bit number.

Lets take it step by step.

When we packed the data, masked each byte and put it in the pack. Here is what it looked like:

    initial data = 10001100 11101001 00001010 00000011

pack = 00000011  // red
pack = 00001010  // green
pack = 11101001  // blue
pack = 10001100  // alpha


As we reassembled the bytes, we followed these steps:

    // Created a 32-bit variable
00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000011

// Added pack (by or-ing), and shifted it left 8 bits
00000000 00000000 00001010 00000011

// Added pack (by or-ing), and shifted it left 16 bits
00000000 11101001 00001010 00000011

// Added pack (by or-ing), and shifted it left 24 bits
10001100 11101001 00001010 00000011


Did it work? Lets check

    Original value: 10001100 11101001 00001010 00000011
Reconstructed : 10001100 11101001 00001010 00000011


It sure looks like it worked!

### Ending remarks

That was a lot of words for me. I don't usually write things for people, but this bitwise stuff is pretty useful and I enjoy it quite a bit.

If you've made it this far and haven't done so yet, you should check out the code I wrote to demonstrate everything.

This was my first article here, I hope I made things clear and didn't goof anything up. If you noticed any mistakes, or if anything is unclear please let me know and I will do my best to clarify things and/or fix them.

### Discussion Hi, Bosley

I write a blog post about bitwise operation of C/C++ recently. I think you may be interested for it so I want to share with you. Here is the link, Convert the endianness in C++ and test it with GDB and Python

Best regards, Gapry.

Thank you for sharing!  