Bitwise Combinational Operators


Uses For Bitwise Operators

Bitwise operators have two main applications. The first is using them to combine several values into a single variable. Suppose you have a series of flag variables which will always have only one of two values: 0 or 1 (this could also be true or false). The smallest unit of memory you can allocate to a variable is a byte, which is eight bits. But why assign each of your flags eight bits, when each one only needs one bit? Using bitwise operators allows you to combine data in this way. The Win32 and DirectX both make liberal use of this. The second application for bitwise operators is that you can use them to accomplish certain arithmetic operations. We’ll take a look at both.

Extracting and Clearing Values

A perfect example for when you’d want to combine multiple values into a single variable is if you’re doing graphics work with 32-bit color. In a 32-bit color dword, there are four distinct values. The low byte (bits 0 through 7) is the value for blue. The next most significant byte is a value for green, then a byte for blue, and finally, the high byte is an alpha (transparency) value. So the color dword looks like this in memory:

AAAA AAAA RRRR RRRR GGGG GGGG BBBB BBBB

Now, suppose you have a 32-bit integer called dwColor, and you want to extract the value for green. How would you do it? What you need is a way to eliminate the other three bytes, and leave the red byte untouched. Recall the truth table for the bitwise AND. If you remember, ANDing any bit with 0 yields 0, and ANDing any bit with 1 yields the original bit. So what you do here is define a value called a mask, which has 0s where you want to erase information, and 1s where you want to save information. Since you want to extract the red byte, your mask would look like this:

0000 0000 1111 1111 0000 0000 0000 0000

Of course, you can’t write binary numbers directly into C code, so you have to convert it into hexadecimal. But that’s easy, remember? In this case, the hex equivalent is 0x00FF0000. If we use the bitwise AND on dwColor and our mask, we get the following result:

dwColor:   AAAA AAAA RRRR RRRR GGGG GGGG BBBB BBBB
mask:    & 0000 0000 1111 1111 0000 0000 0000 0000
         —————————————–
result:    0000 0000 RRRR RRRR 0000 0000 0000 0000

That’s great, but there’s just one problem. To use the red byte by itself like we want, it would have to be the low byte. But it’s not — it’s 16 bits up in the dword. So, what do you think we learned those shift operators for? Posted Image All we need now is a shift right by 16 places, and we’re all set:

Previous:  0000 0000 RRRR RRRR 0000 0000 0000 0000
Shift:                                       >> 16
—————————————
Result:    0000 0000 0000 0000 0000 0000 RRRR RRRR  ==  RRRR RRRR

We’ve done exactly what we wanted to do: we extracted the red byte from the full color dword. This example can be applied to virtually anything that uses bit fields to store a number of values in a single variable. All you have to do is make sure your masks are set correctly, and you shift by the correct number of places. The mask should contain a 1 wherever you want to keep information, and a 0 wherever you want to clear it. As one more example, I’ll show you how you would come up with the masks for a 16-bit color word.

Color word:  RRRR RGGG GGGB BBBB
Red mask:    1111 1000 0000 0000  ==  0xF800
Green mask:  0000 0111 1110 0000  ==  0x07E0
Blue mask:   0000 0000 0001 1111  ==  0x001F

Note that instead of clearing all the fields but one so you can use that by itself, you can also use AND to leave all the fields except one as they are, clearing only that one. For example, you could alter a 32-bit color dword by clearing its green byte. But, then what happens if you want to set that value to something else without altering the rest of the color word? You could accomplish that with the bitwise AND operator and a number of shifts, but it wouldn’t be the most efficient way. To easily splice new values into a larger variable, we need to employ the bitwise OR.

Inserting and Combining Values

Now our situation is the reverse to what we were just doing. Instead of extracting a byte from a color dword, suppose we want to reset one. Maybe we have a color dword that represents the color (214, 53, 240), and we want to change it to (214, 166, 240). The first step is to clear the green byte to 0, which we learned how to do in the last section. To see how to rewrite that byte, consider the truth table for the bitwise OR. Remember that any value ORed with 0 is that value. So we must create a new mask to use. It will have zeroes wherever the color dword is already defined, and it will have an actual color value wherever the color dword has a 0. If you didn’t follow that, this should clear it up:

dwColor:   AAAA AAAA RRRR RRRR 0000 0000 BBBB BBBB
mask:    | 0000 0000 0000 0000 GGGG GGGG 0000 0000
—————————————–
result:    AAAA AAAA RRRR RRRR GGGG GGGG BBBB BBBB

So in this case, the mask is the green byte, located at the appropriate position so that it merges correctly with the color dword. As before, we can use a bitwise shift to shift the green byte into the position we want it in. In the example above, the green byte is located eight bits above the low byte, so the shift operation you’d use would look like this:

Previous:  0000 0000 0000 0000 0000 0000 GGGG GGGG  ==  GGGG GGGG
Shift:                                        << 8
—————————————
Result:    0000 0000 0000 0000 GGGG GGGG 0000 0000

And that’s it! What we’ve done so far with the bitwise AND and OR operations is enough for you to fully manipulate any values divided into bit fields, such as color words. The other place this comes in handy is when you’re designing a function that can take a number of flags as arguments, and you want to combine all of those flags into a single parameter to the function. The only thing you need to do is make sure you define the various flags so that their binary values don’t have any 1s in common. Then you can OR them together to create a unique combination of flags. For example, take a look at the following function call:

Animate(lpdds, 8, ANIM_LOOP | ANIM_MAXSPEED | ANIM_LINK);

This is an example of a function call you might use to start an animation in a game engine. Note that the last parameter to the function has three constants combined using the bitwise OR operator. The definition of those constants might look like this:

#define ANIM_LOOP               1       // (0000 0001)
#define ANIM_ONCE               2       // (0000 0010)
#define ANIM_MAXSPEED   4       // (0000 0100)
#define ANIM_MINSPEED   8       // (0000 1000)
#define ANIM_CUSTSPEED  16      // (0001 0000)
#define ANIM_LINK       32      // (0010 0000)
#define ANIM_LINKALL    64      // (0100 0000)

Note that the constants are defined as successive powers of 2, so that each has only one bit set to 1. This is so any combination of these values will yield a unique result. If you defined them as consecutive integers, you would get repeated values. For example, 1 OR 2 is 3, but 1 OR 3, 2 OR 3, and just 3 by itself all come out to 3 as well. So the function receives a value of 3, it won’t know what combination you mean. To test to see if one of the flags is present, you just try to extract it with an AND. If the result is nonzero, the flag is set. So the body of the function might look like this:

int Animate(LPDIRECTDRAWSURFACE lpdds, int nFrames, DWORD dwFlags)
{
        // test for looping
        if ((dwFlags & ANIM_LOOP) > 0)
                anim.bLoop = TRUE;

        // test for maximum speed
        if ((dwFlags & ANIM_MAXSPEED) > 0)
                anim.nSpeed = MAX_SPEED;

        // ...and so on
}

As I mentioned before, the Win32 API and DirectX both have a great number of functions that let you combine flags in this way, and this is how they accomplish it. If you look through your Windows headers, you’ll find those flags defined as powers of 2 for that very reason. Very useful stuff.

Related posts:

About author

This article was written by admin

Admin has over twenty years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles. Working presently as Development Manager in India. A firm Believer in Knowledge grows when it shared.

Comments

No Comments

Leave your comment

Your email address will not be published. Required fields are marked *