How Bitwise Information Storage Works in 32-bit Int Variables

bitwise-operatorsc

In this book I'm reading I'm going over bitwise operators. Its says the following in the book.

Bitwise operations can potentially store a lot of information in a small amount of memory. Many traits in the world have only two possibilities that are either this way or that way. You are either married or you're not. you are either male or female. In C++, you can store each of these traits in a single bit. This way you can pack 32 separte binary properties into a single 32-bit int.

So is what he saying is when you use bitwise operators in C++ it would only cost 1 bit of memory? I'm not sure what the 32-bit int thing is relevent to and also when he talks about "memory" is this the RAM that the program takes up? Because when I run my C++ programs they are way above 1 bits of ram being ocupied. Am I looking at this in the wrong way?

Best Answer

The book is talking about what is commonly known as bitfields, and their use is often more memory efficient on most platforms, and especially so in serialization or communication contexts. A boolean requires its own address to be usable by the compiler. This means that while, practically, we only need one bit to represent a true (1) or false (0) condition, there is no physical way to address and store one bit in memory. This often means that a boolean will take up an entire byte in memory, just like the smallest integer on that same platform.

Now lets say you had 18 boolean variables. Each one will needs its own addressed piece of memory so that we can reference it elsewhere in the software. That means on our theoretical system we need 18 bytes. People started to see this as a waste of memory, as only one bit out of every byte was really needed.

Enter bitfields. If we look at an integer that matches the system's addressable memory size, we see that it takes up the same number of bits as a single boolean. Integers use all of the bits to represent its range of values. (Decimal value 26 is represented as 00000000 00000000 00000000 00011010 on a 32 bit system, 3572 is 00000000 00000000 00001101 11110100, etc.).

Bitwise operators allow us to play with those bits directly, rather than needing to worry about any real integer value that they were intended to represent. This is important, because if you assign meanings ahead of time to each of those bits, you can set them to 1 and 0 explicitly and treat each bit individually as a boolean.

People love to rip apart analogies but I'm going to give it a shot anyway:

Think of it like a street of houses in a wealthy area full of bachelors. Each home has an address on the street, and each house has 32 rooms, but only one person lives in each house. The bachelors are our booleans. Now lets say a family moves into one of the houses. They are considered one family, but now there are many more people living in the house. This is like our integer - while multiple people are now taking up rooms, we still see it like one house with one value (the family that lives there). Now, another house gets converted to apartments. While its physically still only taking up one house on the street, we assign some letters to each room (Apartment 1A, apartment 2C, etc) that don't affect the physical street address or composition of the house but let us reference each person individually - that's the bit field.

In practice, I'd consider the use of bitfields first instead of booleans as a case of pre-optimization. There are trade-offs in usability; someone else may comment on the trade-offs of speed. Likewise, you can run into issues moving bitfield implementations to different systems if you aren't careful (how would your 32 bit value look on an 8 bit system?) On the flip side, in a small embedded system that I worked on that transferred a ton of status boolean values over a slow serial connection, encoding them as a bitfield was basically a necessity.