Bitwise Operations

Started by
26 comments, last by torakka 17 years, 7 months ago
I've been coming accross bitwise operations a lot in the introductory c++/Visual c++ book I'm reading. Are they important in game programming? I'd also like to know exactly how they work. I can see that combing differnt bits from binary results in a new value with the &/| operators, but how exactly is this used? For example at the end of the chapter the books wants me to write a program the will change the property of a variable so that can be read, write, and appended. Now if you change the bits in a variable wouldn't that change the variable itself and it takes on a new value alltogether? For instance A becomes B. A doesn't become A read only. This is all very confusing to me.
Advertisement
There are a couple of articles on Bitwise Operations here at GameDev. The first I found in a search is:

Bitwise Operations in C

They are a fairly important thing for any programmer to know and understand and are often use to set/check flags that only need to be on or off type things.
Consider the following

#define LVCF_FMT                0x0001#define LVCF_WIDTH              0x0002#define LVCF_TEXT               0x0004#define LVCF_SUBITEM            0x0008lvcColumnZero.mask = LVCF_FMT | LVCF_IMAGE | LVCF_TEXT ;//Format, image and text to be set


lvcColumnZero.mask can now be a single value, containing what effectively amounts to a number of bool's indicating that a particular feature is enabled/disabled.
I'm curious isn't changing the flags also changing the character that is stored in a variable? This is what is confusing me.
Yes, you are changing the variable value but only the bit in that field.

So consider an 8 bit ( char ). You have 8 bits or 'fields' that you can change. Each flag can be represented by one of these fields.

So for example,

ALIVE = 1
DEAD = 2
UNDEAD = 4
GHOST = 8

( note these all go up in powers of 2! )

So we can have a variable: status = 0;

status = 1 => 0000 0001 That means that the ALIVE flag is active
status = 3 => 0000 0011 That means that the ALIVE and the DEAD flag is active
status = 11 => 0000 1011 That means that GHOST/DEAD/ALIVE are all active.

So you can see that the status value can have different values but the ALIVE flag is active in all of them.



That kind of makes sense. Thats for the help everyone.
Yes, exactly. But you need to remember that we are talking 'bit wise'. You change that specific bit, it will change the valule of the number, but the other bits remain unchanged.

lets take the following as an example.

byte var = 0x0000;byte flag1 = 0x0001;//or binary 0000 0001byte flag2 = 0x0002;//or binary 0000 0010byte flag3 = 0x0004;//or binary 0000 0100byte flag3 = 0x0008;//or binary 0000 1000var = flag1 | flag2 | flag3 | flag4;//var now equals binary 0000 1111 because all bits in the low nibble have been set.//what if we want to clear flag3?var = var ^ flag3;//whatever the value of the 2^3 bit, it will be set to zero because of the exclusive or operator.
Quote:Original post by Chris27
I've been coming accross bitwise operations a lot in the introductory c++/Visual c++ book I'm reading. Are they important in game programming?


Seems everyone here gave you a pretty good answer about how bitwise operators work. Now, to answer the question "are they important" the answer really is "that depends". Legacy code is LOADED with bitwise functions, any straight Win32 code uses a ton of #defined bit values.

Now the gotcha, if you are writing new code, I would say HELL NO. People keep using bitwise operators because its habit. Going forward, I can only think of two reasons for you to write code that are bitwise dependant. Those are, 1: it needs to be really condenced, for example, packets of data that are going to go across the network. 2: Its in an extremely tight loop. Even excuse 2 is pretty damned wishy washy as an optimizing compiler can do pretty damned amazing things these days.

I would, 9 times out of 10, recommend the use of an enum(eration) over bit-packing, unless you have a really good reason. The maintainability/readability of your code is well worth any (possible) performance benefits.


Oh, and I guess nobody has told you the reason for using bitwise operators. Generally its to save space. For example, using a single byte, you can now represent 8 yes/no value combinations in a single value.

........
The following post has nothing to do with Chris27's origonal question, it just reminded me of a question I had recently.
..........

Why dont you ever see something like:
#pragma pack(1)
struct _PackedChar {
const unsigned char bitOne :1;
const unsigned char bitTwo :1;
const unsigned char bitThree :1;
const unsigned char bitFour :1;
const unsigned char bitFive :1;
const unsigned char bitSix :1;
const unsigned char bitSeven :1;
const unsigned char bitEight :1;
};
#pragma pack()


I mean, it gives you the advantages of compact data storage, but without the flakeyness of using #define'd bitmasks? Plus, more strongly typed code and compile time checking.

Excuse me if its a stupid question, but I left C++ and all this stuff behind a few years back.
That's a perfectly valid question ;)

I think most people just don't know about bitfields. But also, the "strong type checking" is often inconvenient, especially if you want to set multiple flags at once. You can't say for example "_PackedChar::bitOne | _PackedChar::bitFour". (Not to mention, naming it with an underscore followed by an uppercase letter is a bad idea; those names are reserved.)

However, you're perfectly within your rights to blast anyone who's still using *defines* for bitmasks. They should be using const ints instead, and you should tell them so.

metimmee: ^ (XOR) doesn't "clear" flags; it *toggles* them. To clear flags, AND with the complement of the flags you want to clear (&~).

This topic is closed to new replies.

Advertisement