In the previous lesson on bitwise operators (O.2 -- Bitwise operators), we discussed how the various bitwise operators apply logical operators to each bit within the operands. Now that we understand how they function, let’s take a look at how they’re more commonly used.
Bit masks
In order to manipulate individual bits (e.g. turn them on or off), we need some way to identify the specific bits we want to manipulate. Unfortunately, the bitwise operators don’t know how to work with bit positions. Instead they work with bit masks.
A bit mask is a predefined set of bits that is used to select which specific bits will be modified by subsequent operations.
Consider a real-life case where you want to paint a window frame. If you’re not careful, you risk painting not only the window frame, but also the glass itself. You might buy some masking tape and apply it to the glass and any other parts you don’t want painted. Then when you paint, the masking tape blocks the paint from reaching anything you don’t want painted. In the end, only the non-masked parts (the parts you want painted) get painted.
A bit mask essentially performs the same function for bits -- the bit mask blocks the bitwise operators from touching bits we don’t want modified, and allows access to the ones we do want modified.
Let’s first explore how to define some simple bit masks, and then we’ll show you how to use them.
Defining bit masks in C++14
The simplest set of bit masks is to define one bit mask for each bit position. We use 0s to mask out the bits we don’t care about, and 1s to denote the bits we want modified.
Although bit masks can be literals, they’re often defined as symbolic constants so they can be given a meaningful name and easily reused.
Because C++14 supports binary literals, defining these bit masks is easy:
1 2 3 4 5 6 7 8 9 10 |
#include <cstdint> constexpr std::uint_fast8_t mask0{ 0b0000'0001 }; // represents bit 0 constexpr std::uint_fast8_t mask1{ 0b0000'0010 }; // represents bit 1 constexpr std::uint_fast8_t mask2{ 0b0000'0100 }; // represents bit 2 constexpr std::uint_fast8_t mask3{ 0b0000'1000 }; // represents bit 3 constexpr std::uint_fast8_t mask4{ 0b0001'0000 }; // represents bit 4 constexpr std::uint_fast8_t mask5{ 0b0010'0000 }; // represents bit 5 constexpr std::uint_fast8_t mask6{ 0b0100'0000 }; // represents bit 6 constexpr std::uint_fast8_t mask7{ 0b1000'0000 }; // represents bit 7 |
Now we have a set of symbolic constants that represents each bit position. We can use these to manipulate the bits (which we’ll show how to do in just a moment).
Defining bit masks in C++11 or earlier
Because C++11 doesn’t support binary literals, we have to use other methods to set the symbolic constants. There are two good methods for doing this. Less comprehensible, but more common, is to use hexadecimal. If you need a refresher on hexadecimal, please revisit lesson 4.12 -- Literals.
1 2 3 4 5 6 7 8 |
constexpr std::uint_fast8_t mask0{ 0x1 }; // hex for 0000 0001 constexpr std::uint_fast8_t mask1{ 0x2 }; // hex for 0000 0010 constexpr std::uint_fast8_t mask2{ 0x4 }; // hex for 0000 0100 constexpr std::uint_fast8_t mask3{ 0x8 }; // hex for 0000 1000 constexpr std::uint_fast8_t mask4{ 0x10 }; // hex for 0001 0000 constexpr std::uint_fast8_t mask5{ 0x20 }; // hex for 0010 0000 constexpr std::uint_fast8_t mask6{ 0x40 }; // hex for 0100 0000 constexpr std::uint_fast8_t mask7{ 0x80 }; // hex for 1000 0000 |
This can be a little hard to read. One way to make it easier is to use the left-shift operator to shift a bit into the proper location:
1 2 3 4 5 6 7 8 |
constexpr std::uint_fast8_t mask0{ 1 << 0 }; // 0000 0001 constexpr std::uint_fast8_t mask1{ 1 << 1 }; // 0000 0010 constexpr std::uint_fast8_t mask2{ 1 << 2 }; // 0000 0100 constexpr std::uint_fast8_t mask3{ 1 << 3 }; // 0000 1000 constexpr std::uint_fast8_t mask4{ 1 << 4 }; // 0001 0000 constexpr std::uint_fast8_t mask5{ 1 << 5 }; // 0010 0000 constexpr std::uint_fast8_t mask6{ 1 << 6 }; // 0100 0000 constexpr std::uint_fast8_t mask7{ 1 << 7 }; // 1000 0000 |
Testing a bit (to see if it is on or off)
Now that we have a set of bit masks, we can use these in conjunction with a bit flag variable to manipulate our bit flags.
To determine if a bit is on or off, we use bitwise AND in conjunction with the bit mask for the appropriate bit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <cstdint> #include <iostream> int main() { constexpr std::uint_fast8_t mask0{ 0b0000'0001 }; // represents bit 0 constexpr std::uint_fast8_t mask1{ 0b0000'0010 }; // represents bit 1 constexpr std::uint_fast8_t mask2{ 0b0000'0100 }; // represents bit 2 constexpr std::uint_fast8_t mask3{ 0b0000'1000 }; // represents bit 3 constexpr std::uint_fast8_t mask4{ 0b0001'0000 }; // represents bit 4 constexpr std::uint_fast8_t mask5{ 0b0010'0000 }; // represents bit 5 constexpr std::uint_fast8_t mask6{ 0b0100'0000 }; // represents bit 6 constexpr std::uint_fast8_t mask7{ 0b1000'0000 }; // represents bit 7 std::uint_fast8_t flags{ 0b0000'0101 }; // 8 bits in size means room for 8 flags std::cout << "bit 0 is " << ((flags & mask0) ? "on\n" : "off\n"); std::cout << "bit 1 is " << ((flags & mask1) ? "on\n" : "off\n"); return 0; } |
This prints:
bit 0 is on bit 1 is off
Setting a bit
To set (turn on) a bit, we use bitwise OR equals (operator |=) in conjunction with the bit mask for the appropriate bit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <cstdint> #include <iostream> int main() { constexpr std::uint_fast8_t mask0{ 0b0000'0001 }; // represents bit 0 constexpr std::uint_fast8_t mask1{ 0b0000'0010 }; // represents bit 1 constexpr std::uint_fast8_t mask2{ 0b0000'0100 }; // represents bit 2 constexpr std::uint_fast8_t mask3{ 0b0000'1000 }; // represents bit 3 constexpr std::uint_fast8_t mask4{ 0b0001'0000 }; // represents bit 4 constexpr std::uint_fast8_t mask5{ 0b0010'0000 }; // represents bit 5 constexpr std::uint_fast8_t mask6{ 0b0100'0000 }; // represents bit 6 constexpr std::uint_fast8_t mask7{ 0b1000'0000 }; // represents bit 7 std::uint_fast8_t flags{ 0b0000'0101 }; // 8 bits in size means room for 8 flags std::cout << "bit 1 is " << ((flags & mask1) ? "on\n" : "off\n"); flags |= mask1; // turn on bit 1 std::cout << "bit 1 is " << ((flags & mask1) ? "on\n" : "off\n"); return 0; } |
This prints:
bit 1 is off bit 1 is on
We can also turn on multiple bits at the same time using Bitwise OR:
1 |
flags |= (mask4 | mask5); // turn bits 4 and 5 on at the same time |
Resetting a bit
To clear a bit (turn off), we use Bitwise AND and Bitwise NOT together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <cstdint> #include <iostream> int main() { constexpr std::uint_fast8_t mask0{ 0b0000'0001 }; // represents bit 0 constexpr std::uint_fast8_t mask1{ 0b0000'0010 }; // represents bit 1 constexpr std::uint_fast8_t mask2{ 0b0000'0100 }; // represents bit 2 constexpr std::uint_fast8_t mask3{ 0b0000'1000 }; // represents bit 3 constexpr std::uint_fast8_t mask4{ 0b0001'0000 }; // represents bit 4 constexpr std::uint_fast8_t mask5{ 0b0010'0000 }; // represents bit 5 constexpr std::uint_fast8_t mask6{ 0b0100'0000 }; // represents bit 6 constexpr std::uint_fast8_t mask7{ 0b1000'0000 }; // represents bit 7 std::uint_fast8_t flags{ 0b0000'0101 }; // 8 bits in size means room for 8 flags std::cout << "bit 2 is " << ((flags & mask2) ? "on\n" : "off\n"); flags &= ~mask2; // turn off bit 2 std::cout << "bit 2 is " << ((flags & mask2) ? "on\n" : "off\n"); return 0; } |
This prints:
bit 2 is on bit 2 is off
We can turn off multiple bits at the same time:
1 |
flags &= ~(mask4 | mask5); // turn bits 4 and 5 off at the same time |
Flipping a bit
To toggle a bit state, we use Bitwise XOR:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <cstdint> #include <iostream> int main() { constexpr std::uint_fast8_t mask0{ 0b0000'0001 }; // represents bit 0 constexpr std::uint_fast8_t mask1{ 0b0000'0010 }; // represents bit 1 constexpr std::uint_fast8_t mask2{ 0b0000'0100 }; // represents bit 2 constexpr std::uint_fast8_t mask3{ 0b0000'1000 }; // represents bit 3 constexpr std::uint_fast8_t mask4{ 0b0001'0000 }; // represents bit 4 constexpr std::uint_fast8_t mask5{ 0b0010'0000 }; // represents bit 5 constexpr std::uint_fast8_t mask6{ 0b0100'0000 }; // represents bit 6 constexpr std::uint_fast8_t mask7{ 0b1000'0000 }; // represents bit 7 std::uint_fast8_t flags{ 0b0000'0101 }; // 8 bits in size means room for 8 flags std::cout << "bit 2 is " << ((flags & mask2) ? "on\n" : "off\n"); flags ^= mask2; // flip bit 2 std::cout << "bit 2 is " << ((flags & mask2) ? "on\n" : "off\n"); flags ^= mask2; // flip bit 2 std::cout << "bit 2 is " << ((flags & mask2) ? "on\n" : "off\n"); return 0; } |
This prints:
bit 2 is on bit 2 is off bit 2 is on
We can flip multiple bits simultaneously:
1 |
flags ^= (mask4 | mask5); // flip bits 4 and 5 at the same time |
Bit masks and std::bitset
std::bitset supports the full set of bitwise operators. So even though it’s easier to use the functions (test, set, reset, and flip) to modify individual bits, you can use bitwise operators and bit masks if you want.
Why would you want to? The functions only allow you to modify individual bits. The bitwise operators allow you to modify multiple bits at once.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <cstdint> #include <iostream> #include <bitset> int main() { constexpr std::bitset<8> mask0{ 0b0000'0001 }; // represents bit 0 constexpr std::bitset<8> mask1{ 0b0000'0010 }; // represents bit 1 constexpr std::bitset<8> mask2{ 0b0000'0100 }; // represents bit 2 constexpr std::bitset<8> mask3{ 0b0000'1000 }; // represents bit 3 constexpr std::bitset<8> mask4{ 0b0001'0000 }; // represents bit 4 constexpr std::bitset<8> mask5{ 0b0010'0000 }; // represents bit 5 constexpr std::bitset<8> mask6{ 0b0100'0000 }; // represents bit 6 constexpr std::bitset<8> mask7{ 0b1000'0000 }; // represents bit 7 std::bitset<8> flags{ 0b0000'0101 }; // 8 bits in size means room for 8 flags std::cout << "bit 1 is " << (flags.test(1) ? "on\n" : "off\n"); std::cout << "bit 2 is " << (flags.test(2) ? "on\n" : "off\n"); flags ^= (mask1 | mask2); // flip bits 1 and 2 std::cout << "bit 1 is " << (flags.test(1) ? "on\n" : "off\n"); std::cout << "bit 2 is " << (flags.test(2) ? "on\n" : "off\n"); flags |= (mask1 | mask2); // turn bits 1 and 2 on std::cout << "bit 1 is " << (flags.test(1) ? "on\n" : "off\n"); std::cout << "bit 2 is " << (flags.test(2) ? "on\n" : "off\n"); flags &= ~(mask1 | mask2); // turn bits 1 and 2 off std::cout << "bit 1 is " << (flags.test(1) ? "on\n" : "off\n"); std::cout << "bit 2 is " << (flags.test(2) ? "on\n" : "off\n"); return 0; } |
This prints:
bit 1 is off bit 2 is on bit 1 is on bit 2 is off bit 1 is on bit 2 is on bit 1 is off bit 2 is off
Making bit masks meaningful
Naming our bit masks “mask1” or “mask2” tells us what bit is being manipulated, but doesn’t give us any indication of what that bit flag is actually being used for.
A best practice is to give your bit masks useful names as a way to document the meaning of your bit flags. Here’s an example from a game we might write:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <cstdint> #include <iostream> int main() { // Define a bunch of physical/emotional states constexpr std::uint_fast8_t isHungry{ 1 << 0 }; // 0000 0001 constexpr std::uint_fast8_t isSad{ 1 << 1 }; // 0000 0010 constexpr std::uint_fast8_t isMad{ 1 << 2 }; // 0000 0100 constexpr std::uint_fast8_t isHappy{ 1 << 3 }; // 0000 1000 constexpr std::uint_fast8_t isLaughing{ 1 << 4 }; // 0001 0000 constexpr std::uint_fast8_t isAsleep{ 1 << 5 }; // 0010 0000 constexpr std::uint_fast8_t isDead{ 1 << 6 }; // 0100 0000 constexpr std::uint_fast8_t isCrying{ 1 << 7 }; // 1000 0000 std::uint_fast8_t me{}; // all flags/options turned off to start me |= (isHappy | isLaughing); // I am happy and laughing me &= ~isLaughing; // I am no longer laughing // Query a few states // (we'll use static_cast<bool> to interpret the results as a boolean value) std::cout << "I am happy? " << static_cast<bool>(me & isHappy) << '\n'; std::cout << "I am laughing? " << static_cast<bool>(me & isLaughing) << '\n'; return 0; } |
Here’s the same example implemented using std::bitset:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <iostream> #include <bitset> int main() { // Define a bunch of physical/emotional states std::bitset<8> isHungry{ 0b0000'0001 }; std::bitset<8> isSad{ 0b0000'0010 }; std::bitset<8> isMad{ 0b0000'0100 }; std::bitset<8> isHappy{ 0b0000'1000 }; std::bitset<8> isLaughing{ 0b0001'0000 }; std::bitset<8> isAsleep{ 0b0010'0000 }; std::bitset<8> isDead{ 0b0100'0000 }; std::bitset<8> isCrying{ 0b1000'0000 }; std::bitset<8> me{}; // all flags/options turned off to start me |= (isHappy | isLaughing); // I am happy and laughing me &= ~isLaughing; // I am no longer laughing // Query a few states (we use the any() function to see if any bits remain set) std::cout << "I am happy? " << (me & isHappy).any() << '\n'; std::cout << "I am laughing? " << (me & isLaughing).any() << '\n'; return 0; } |
Two notes here: First, std::bitset doesn’t have a nice function that allows you to query bits using a bit mask. So if you want to use bit masks rather than positional indexes, you’ll have to use Bitwise AND to query bits. Second, we make use of the any() function, which returns true if any bits are set, and false otherwise to see if the bit we queried remains on or off.
When are bit flags most useful?
Astute readers may note that the above examples don’t actually save any memory. 8 booleans would normally take 8 bytes. But the above examples use 9 bytes (8 bytes to define the bit masks, and 1 bytes for the flag variable)!
Bit flags make the most sense when you have many identical flag variables. For example, in the example above, imagine that instead of having one person (me), you had 100. If you used 8 Booleans per person (one for each possible state), you’d use 800 bytes of memory. With bit flags, you’d use 8 bytes for the bit masks, and 100 bytes for the bit flag variables, for a total of 108 bytes of memory -- approximately 8 times less memory.
For most programs, the amount of memory using bit flags saved is not worth the added complexity. But in programs where there are tens of thousands or even millions of similar objects, using bit flags can reduce memory use substantially. It’s a useful optimization to have in your toolkit if you need it.
There’s another case where bit flags and bit masks can make sense. Imagine you had a function that could take any combination of 32 different options. One way to write that function would be to use 32 individual Boolean parameters:
1 |
void someFunction(bool option1, bool option2, bool option3, bool option4, bool option5, bool option6, bool option7, bool option8, bool option9, bool option10, bool option11, bool option12, bool option13, bool option14, bool option15, bool option16, bool option17, bool option18, bool option19, bool option20, bool option21, bool option22, bool option23, bool option24, bool option25, bool option26, bool option27, bool option28, bool option29, bool option30, bool option31, bool option32); |
Hopefully you’d give your parameters more descriptive names, but the point here is to show you how obnoxiously long the parameter list is.
Then when you wanted to call the function with options 10 and 32 set to true, you’d have to do so like this:
1 |
someFunction(false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true); |
This is ridiculously difficult to read (is that option 9, 10, or 11 that’s set to true?), and also means you have to remember which argument corresponds to which option (is setting the “edit flag” the 9th, 10th, or 11th parameter?) It may also not be very performant, as every function call has to copy 32 booleans from the caller to the function.
Instead, if you defined the function using bit flags like this:
1 |
void someFunction(std::bitset<32> options); |
Then you could use bit flags to pass in only the options you wanted:
1 |
someFunction(option10 | option32); |
Not only is this much more readable, it’s likely to be more performant as well, since it only involves 2 operations (one Bitwise OR and one parameter copy).
This is one of the reasons OpenGL, a well regarded 3d graphic library, opted to use bit flag parameters instead of many consecutive Boolean parameters.
Here’s a sample function call from OpenGL:
1 |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the color and the depth buffer |
GL_COLOR_BUFFER_BIT and GL_DEPTH_BUFFER_BIT are bit masks defined as follows (in gl2.h):
1 2 3 |
#define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 |
Bit masks involving multiple bits
Although bit masks often are used to select a single bit, they can also be used to select multiple bits. Lets take a look at a slightly more complicated example where we do this.
Color display devices such as TVs and monitors are composed of millions of pixels, each of which can display a dot of color. The dot of color is composed from three beams of light: one red, one green, and one blue (RGB). By varying the intensity of the colors, any color on the color spectrum can be made. Typically, the amount of R, G, and B for a given pixel is represented by an 8-bit unsigned integer. For example, a red pixel would have R=255, G=0, B=0. A purple pixel would have R=255, G=0, B=255. A medium-grey pixel would have R=127, G=127, B=127.
When assigning color values to a pixel, in addition to R, G, and B, a 4th value called A is often used. “A” stands for “alpha”, and it controls how transparent the color is. If A=0, the color is fully transparent. If A=255, the color is opaque.
R, G, B, and A are normally stored as a single 32-bit integer, with 8 bits used for each component:
32-bit RGBA value | |||
bits 31-24 | bits 23-16 | bits 15-8 | bits 7-0 |
RRRRRRRR | GGGGGGGG | BBBBBBBB | AAAAAAAA |
red | green | blue | alpha |
The following program asks the user to enter a 32-bit hexadecimal value, and then extracts the 8-bit color values for R, G, B, and A.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include <cstdint> #include <iostream> int main() { constexpr std::uint_fast32_t redBits{ 0xFF000000 }; constexpr std::uint_fast32_t greenBits{ 0x00FF0000 }; constexpr std::uint_fast32_t blueBits{ 0x0000FF00 }; constexpr std::uint_fast32_t alphaBits{ 0x000000FF }; std::cout << "Enter a 32-bit RGBA color value in hexadecimal (e.g. FF7F3300): "; std::uint_fast32_t pixel{}; std::cin >> std::hex >> pixel; // std::hex allows us to read in a hex value // use Bitwise AND to isolate red pixels, // then right shift the value into the lower 8 bits std::uint_fast8_t red{ static_cast<std::uint_fast8_t>((pixel & redBits) >> 24) }; std::uint_fast8_t green{ static_cast<std::uint_fast8_t>((pixel & greenBits) >> 16) }; std::uint_fast8_t blue{ static_cast<std::uint_fast8_t>((pixel & blueBits) >> 8) }; std::uint_fast8_t alpha{ static_cast<std::uint_fast8_t>(pixel & alphaBits) }; std::cout << "Your color contains:\n"; std::cout << std::hex; // print the following values in hex std::cout << static_cast<int>(red) << " red\n"; std::cout << static_cast<int>(green) << " green\n"; std::cout << static_cast<int>(blue) << " blue\n"; std::cout << static_cast<int>(alpha) << " alpha\n"; return 0; } |
This produces the output:
Enter a 32-bit RGBA color value in hexadecimal (e.g. FF7F3300): FF7F3300 Your color contains: ff red 7f green 33 blue 0 alpha
In the above program, we use a bitwise AND to query the set of 8 bits we’re interested in, and then we right shift them into an 8-bit value so we can print them back as hex values.
Summary
Summarizing how to set, clear, toggle, and query bit flags:
To query bit states, we use bitwise AND:
1 |
if (flags & option4) ... // if option4 is set, do something |
To set bits (turn on), we use bitwise OR:
1 2 |
flags |= option4; // turn option 4 on. flags |= (option4 | option5); // turn options 4 and 5 on. |
To clear bits (turn off), we use bitwise AND with bitwise NOT:
1 2 |
flags &= ~option4; // turn option 4 off flags &= ~(option4 | option5); // turn options 4 and 5 off |
To flip bit states, we use bitwise XOR:
1 2 |
flags ^= option4; // flip option4 from on to off, or vice versa flags ^= (option4 | option5); // flip options 4 and 5 |
Quiz time
Question #1
Do not use std::bitset
in this quiz. We’re only using std::bitset
for printing.
Given the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <bitset> #include <cstdint> #include <iostream> int main() { constexpr std::uint_fast8_t option_viewed{ 0x01 }; constexpr std::uint_fast8_t option_edited{ 0x02 }; constexpr std::uint_fast8_t option_favorited{ 0x04 }; constexpr std::uint_fast8_t option_shared{ 0x08 }; constexpr std::uint_fast8_t option_deleted{ 0x10 }; std::uint_fast8_t myArticleFlags{ option_favorited }; // ... std::cout << std::bitset<8>{ myArticleFlags } << '\n'; return 0; } |
a) Write a line of code to set the article as viewed.
Expected output:
00000101
b) Write a line of code to check if the article was deleted.
c) Write a line of code to clear the article as a favorite.
Expected output (Assuming you did quiz (a)):
00000001
1d) Extra credit: why are the following two lines identical?
1 2 |
myflags &= ~(option4 | option5); // turn options 4 and 5 off myflags &= ~option4 & ~option5; // turn options 4 and 5 off |
![]() |
![]() |
![]() |
Hey guys just needed help again because its getting harder and harder as the chapters move on.
so the way i understand it is that since the smallest size of a variable is 1 byte we make use of the bits in a byte to store 8 Boolean values in 1 variable.
but isn't this also going to use up 1 byte for each mask we create ?
constexpr std::bitset<8> mask0{ 0b0000'0001 }; // represents bit 0 isnt mask0 going to take up 1 byte ?
constexpr std::bitset<8> mask1{ 0b0000'0010 }; // represents bit 1 isnt mask1 going to take up 1 byte too ?
constexpr std::bitset<8> mask2{ 0b0000'0100 }; // represents bit 2
constexpr std::bitset<8> mask3{ 0b0000'1000 }; // represents bit 3
constexpr std::bitset<8> mask4{ 0b0001'0000 }; // represents bit 4
constexpr std::bitset<8> mask5{ 0b0010'0000 }; // represents bit 5
constexpr std::bitset<8> mask6{ 0b0100'0000 }; // represents bit 6
constexpr std::bitset<8> mask7{ 0b1000'0000 }; // represents bit 7 so in total we created 8 variables each a 1 byte variable ?
so if i create a separate 1byte integer type for a single Boolean variable it doesn't make a difference in memory space ?
You can reuse the masks for an infinite amount of flag variables
ah i see.. thanks very much.
although , in an attempt to make our bit mask meaningful we do this
// Define a bunch of physical/emotional states
constexpr std::uint_fast8_t isHungry{ 1 << 0 }; // 0000 0001
constexpr std::uint_fast8_t isSad{ 1 << 1 }; // 0000 0010
constexpr std::uint_fast8_t isMad{ 1 << 2 }; // 0000 0100
constexpr std::uint_fast8_t isHappy{ 1 << 3 }; // 0000 1000
constexpr std::uint_fast8_t isLaughing{ 1 << 4 }; // 0001 0000
constexpr std::uint_fast8_t isAsleep{ 1 << 5 }; // 0010 0000
constexpr std::uint_fast8_t isDead{ 1 << 6 }; // 0100 0000
constexpr std::uint_fast8_t isCrying{ 1 << 7 }; // 1000 0000
doesn't this mean that each mask is now specific to a single byte size variable and would now not make sense if used on a second single byte variable with different meanings ?
like say 1 byte variables characterStatus and carStatus ... its now senseless to use isHappy for carStatus..
EDIT : never mind im stupid. all is explained further down below in the "When are bit flags most useful?" section. i just had to read further. sorry
`mask1`, `mask2`, etc. are meaningless and shouldn't occur in the wild. `isHungry` etc. is a real example.
You can't mix `characterStatus` and `carStatus`. But you might have more than 1 character or more than 1 car.
Even if you only have 1 character or 1 car, you'll save memory when you need to serialize the value, eg. when sending the value over the network or writing it to a file.
If you know that you'll only have 1 of these values and you'll never need to serialize it in a memory-friendly way, using a `bool` for each option is the easier solution.
Never mind I'm stupid, you already found it. I just had to read further :D
thanks ! haha :D
May I suggest to remove the std::cout << std::hex; line from the RGBA example?
I think it's redundant to show the result in hex, since thats exactly what we input in first place. It's a lot more interesting to show the unsigned integer of each color:
FF7F3300 is composed of:
255 red
127 green
51 blue
0 alpha
Another great lesson!
1. Line 17 in the code block in section "Making bit masks meaningful":
>
`isHappy | isLaughing` should be between parentheses for consistency with previous examples. Same goes for line 18 in the next code block.
2. In section "When are bit flags most useful?"
> you have to remember which parameters corresponds to which option
I think "correspond" should be used instead, but I'm not 100% sure.
3. Question #1
> Do not use std::bitset in this quiz. We’re only using std::bitset to for printing.
I don't think "to" should be here.
Visual Studio tip:
Hold Ctrl + Alt and click somewhere to create a new cursor/caret. This will let you make edits in multiple places at once. Useful for creating bitmask const variables with binary literals.
Can you explain how this code works?
Pixel is a 32 bit variable where the user has inserted some value. Variables redBits, greenBits, blueBits and alphaBits are 8-bit bit masks that are used to select specific bits from pixel. When we say e.g pixel & redBits, we choose the last 8 bits of the variable named pixel, because those are what the mask redBits corresponds for. The sifting operation >> is done, because we need the bits to be in the rightmost positions of the unsigned integers so that we can represent them as hexadecimal values correctly, so the leftmost 8 bits on positions 24-31 are sifted 24 steps to the right etc. Otherwise after the & operation we would have FF000000, which is not what we wanted.
Hello! Could you please explain following example in a little bit more details as i am getting confused at some parts. I will list what i need additional support with below the example.
1. How would you brace initialize RGBA variables using static cast? Just one example on "red" and why you want to avoid using static cast? More complicated?
2. You are using std::hex to print values in hex at the end and using static cast <int> as well. Could you explain why exactly we have to use static cast <int> to display RGBA variables? Is it because these values are currently set in binary? But even though they are in binary, why i cannot just use std::cout<<std::hex and then std::cout<<red<<"red\n"? Doing so i am expecting binary "red" to be automatically converted to hex "red" because i am using std::cout<<std::hex prior to print "red" variable. Am i am missing something from lessons about conversion and printing values in different numerical systems?
Thanks for the answer in advance
1. Neither `auto` nor `static_cast` were fully introduced yet, that's probably why the `static_cast` was avoided here. I've updated the example to use the `static_cast` anyway, because it's used elsewhere too, even though the code gets messy without `auto`.
2. The variables being printed are `std::uint_fast8_t`, which might be an `unsigned char`. If that's the case, `std::cout` would interpret them as characters, not numbers. The numbering system you use doesn't affect the value. Numbering systems are merely an aid for humans. For a computer, everything is binary. Saying "a value is set in binary" doesn't make sense.
Many thanks, it is all clear now!
Is it fine to write this line of code below for question #1 b) ?
(myArticleFlags & option_deleted) ? (std::cout << "The article has been deleted.") : (std::cout << "The article has not been deleted.");
The conditional operator should only be used if you need the return value of the expressions. If you don't need the return value, use an if-statement.
1. any()
Is there an explaination for it? It just pops up out of the blue at the end of the example.
2. For Question 1a)
Could you kindly show what the output is in the console?
With your code, I got a smiley face. ☺☺☺
With my code, I got a 1.
1. The explanation is in the paragraph after the example.
2. The output is implementation-defined, because `std::uint_fast8_t` is an implementation-defined type. If `std::uint_fast8_t` is an `unsigned char`, the output should be a SOH (Start of Heading) character (invisible). If it is another integer type, the output should be 1. I don't know how you managed to get a smiley face. If your `std::uint_fast8_t` is an `unsigned char`, `(myArticleFlags | option_viewed)` promotes the result to an `int` or `unsigned int`, which is why you can get different results compared to printing `myArticleFlags`.
Hi, do you have an email?
I'll snapshot the smileyface and email it to you.
I assume the answer should be 0x01.
Could you print out the answer and add it to Quiz 1a)?
I'm not sure if I'm doing it correctly if I see a smiley face appear as the answer.
Seeing the smiley won't help me. The smiley you posted is "\u263a", very much not what the value of `myArticleFlags` should be. If you want to print the value as an integer, you can use `std::cout << static_cast(myArticleFlags) << '\n';`.
I've added expected outputs to quiz (a) and (c), thanks for the suggestion!
Hello!
May i ask why in all your examples you use uint_fast8_t, while in previous lessons it was shown as the best practice to avoid using 8 bit integers since C++ may consider them as chars?
You said:
"We use 0s to mask out the bits we don’t care about, and 1s to denote the bits we want modified."
Where do you use 0s in this lesson to "mask out" bits and 1s to "denote bits"? And how does 0s and 1s mask out or in bits?
You said that "cstdint" probably stands for "standard integer" that’s what I knew but what I don’t know is what does the "c" stand for?
means that we include the C++ version "..." library
Thus,
means we include the C++ version of stdint.h library
Cannot reply to comments, also there’s no timer to edit a comment.
How does flags "|= mask1" turn on a bit?
"standard integer" probably.
There are many `flags` on this page. The `flags` in "Summary" assumes there is a `flags` bitset or integer, it doesn't matter.
You said that "cstdint" probably stands for "standard integer" that’s what I knew but what I don’t know is what does the "c" stand for?
I don't know what the "c" stands for. It might mean that the header originates from C. eg. cstdint is stdint.h in C.
Can you explain How flags "|= mask1" turns on a bit?
`flags |= mask1` is the same as `flags = flags | mask1`
How does "flags = flags | mask1" torn on a bit?
turn*
See lesson O.2 section "Bitwise OR"
I know what bitwise or is and that’s why I’m asking why is it needed an or why not "flags = mask1" ? so it declares flags as mask1 that is on.
`flags = mask1` would override all bits, but you want to set those bits to 1 that are 1 in `mask1` and not touch the others
I don’t get it. What does flags bitwise or equals mask1 mean? More precise: What does or equals mean?
It's like
which means:
so
is the same as
[code]flags = flags | mask1[code]
I suggest you to go at the section "Bitwise assignment operators" of the previous lesson (O.2)
I’m stuck here, can you reply?
I don't know what more to say. I suggest you move on to other lessons and come back to bitwise operations when you need them.
Let me try to explain this how I understood it.
Let's say
flags = 0101
mask = 0010
flags |= mask is the same as flags = flags|mask
To visualize the procedure like it was done in previous lessons, we can show it like this:
0101 (flags)
OR 0010 (masks)
--------
0111 (new flags)
So the second bit from the right was turned on using the mask.
How is flags |= mask1 the same as flags | mask1 ? = is a assignment and how is flags | assigned to mask1 like flags | mask1 ?
Why is it needed an | (or) to assign flags to mask1 why is it not just flags = mask1?
Because the "=" means assignment which means:
for example:
and
if we do:
The variable "flags" would be 0b0000'0010
whereas if we do:
which means
It assigns the "flags bitOR mask1" to the variable flags which means flags = 0b0000'0101 | 0b0000'0010
What does "cstdint" stand for?
And where was flags defined?
We use hexadecimal values only because inputting binary values for all the 32 bits is time elapsing. Right?
I have a doubt. Maybe it's silly. In the program which asks the user to enter a 32-bit hexadecimal value, and then extracts the 8-bit color values for R, G, B, and A, we assign 0xFF000000 to the red extractor. When the user enters a value, he/she enters a value of 8 bit long. I don't understand this. We are defining 32bit long value and inputting and operating using 8 bit long values.
The user enters 0xFF000000, which is a 32bit value. The program splits this 32bit value into 4 8bit values.
You mean, the limit for the data type is 32 bits? How's FF000000 32 bit value??? It's 8 bits isn't it?
FF is the largest 8bit value. Anything beyond FF doesn't fit into 8 bits.
FF000000 is a 32bit value.
Maybe you're being confused by the trailing zeros. hex(FF000000) is dec(4278190080).
Oh yeah yeah. It's all clear now. Thank you for helping me understand. And I am amazed by the way you keep this website updated and answer every questions asked. May God bless you and your team. Keep helping others✌
Masktape is not the appropriate example to bitmask because it’s the opposite, masking against paint is for the cause to exclude the masked part but with bitmask it’s the cause of using only that bit and excluding all other bits.
thanks
when i finshed the last lesson i did some functions to do set,reset,test,flip
before i know about bit masks
i want to know are my functions is usable or not ?
sorry for bad english
here is my code :
#include <iostream>
#include <bitset>
#define typeOfNumber unsigned char // type of bitflags(should be unisgned integer)
constexpr char numberOfBits{ 8 }; // should identical with the type above
// to give me the position (i didn't now about the bit masks yet)
int expontaion(int value, int exponent) {
int theResult{ 1 };
for (;exponent > 0;exponent--) {
theResult *= value;
}
return theResult;
}
// set bit to 1
void setBit(typeOfNumber & bitFlags, typeOfNumber position)
{
position = expontaion(2, position);
bitFlags = bitFlags | position;
}
// set bit to 0
void reSetBit(typeOfNumber& bitFlags, typeOfNumber position)
{
position = expontaion(2, position);
if ((bitFlags & position) == position)
bitFlags ^= position;
}
// if bit is 0 set it to 1 (vice versa)
void flipBit(typeOfNumber& bitFlags, unsigned typeOfNumber position)
{
position = expontaion(2, position);
bitFlags = bitFlags ^ position;
}
//test bit
typeOfNumber getBit(typeOfNumber bitFlags, typeOfNumber position)
{
bitFlags = bitFlags << (numberOfBits - 1) - position;
bitFlags = bitFlags >>( numberOfBits - 1);
return bitFlags;
}
int main() {
unsigned char infoBitFlags{0b1010'1010};
setBit(infoBitFlags, 0); // set position 1 in infoBitFlags to 1
std::cout << std::bitset<8>{infoBitFlags} << '\n'; //this will print 1010'1011
return 0;
}
I don't know what it particularly is but, it feels like I didn't understand something. I even read these chapters a couple of times, thoroughly too, but it still feels like I am not completely sure about it. It might have to do with bits and bytes and values, I don't know. Due to this I have not been able to proceed further...
lmao same
Try subbing in the values and test it out. For example if we test if mask1 is turned on. We can do (flag & mask1)
Subbing in we get:
0000'0101 &
0000'0010
---------
0000'0000
Remember that for '&', both bytes have to be true (1). Since all the whole byte is false(they are all 0), we can say that mask1 is turned off.
You may notice the bytes that are turned on have at least 1 true bit for flag & masknumber.
So when we are turning on a bit, we use OR '|', which means at least one or more bit have to be true(1). This guarentees that at least one of the bytes will have a 1, for example:
flag |= mask1 =
0000'0101 OR
0000'0010
---------
0000'0111 As there is more than one true bit, mask1 is turned on.
Now lets see what we get when we turn off a bit.
From the first example above, we are told that mask2 = 0000'0100 is turned on.
We can turn it off with flag &= ~mask2. Let's see how it works:
~mask2 = 1111'1011.
flag = flag & ~mask2 is:
0000'0101 AND
1111'1011
---------
0000'0000
Since all the bits are 0, we say that mask2 is turned off now.
I might be completely wrong, but this is the way I understood this chapter. Please correct me if I'm wrong in anything.
Hi there, awesome series of lessons you've all got going here, really appreciate the effort that goes into maintaining a site like this, kudos!
I have a question regarding the final example before the summary. As far as I can tell, my code is identical to that provided in the example;
However I keep receiving a compiler warning telling me my green RGBA component variable in main() is being initialized with a 'possible loss of data', implying that the data lost are the zeros resulting from the 16 right bitshifts of (green & greenMask), even though the other component variables all compile with no issue at all. I had to disable treating warnings as errors in order for my program to compile. Suffice to say that it works fine, so I'm just wondering why I am receiving the aforementioned warning? Thanks in advance.
constexpr std::uint_fast8_t isHungry{ 1 << 0 }; // 0000 0001
constexpr std::uint_fast8_t isSad{ 1 << 1 }; // 0000 0010
constexpr std::uint_fast8_t isMad{ 1 << 2 }; // 0000 0100
constexpr std::uint_fast8_t isHappy{ 1 << 3 }; // 0000 1000
constexpr std::uint_fast8_t isLaughing{ 1 << 4 }; // 0001 0000
constexpr std::uint_fast8_t isAsleep{ 1 << 5 }; // 0010 0000
constexpr std::uint_fast8_t isDead{ 1 << 6 }; // 0100 0000
constexpr std::uint_fast8_t isCrying{ 1 << 7 }; // 1000 0000
Why are we not using binary numbers here, but a left shift? And how the value of 1 is evaluated.
#include <iostream>
#include <cstdint>
#include <bitset>
int main()
{
constexpr std::uint_fast8_t option1{ 0b0000'0000 };
constexpr std::uint_fast8_t option2{ 0b0000'0001 };
constexpr std::uint_fast8_t option3{ 0b0000'0010 };
constexpr std::uint_fast8_t option4{ 0b0000'0100 };
constexpr std::uint_fast8_t option5{ 0b0000'1000 };
constexpr std::uint_fast8_t option6{ 0b0001'0000 };
constexpr std::uint_fast8_t option7{ 0b0010'0000 };
constexpr std::uint_fast8_t option8{ 0b0100'0000 };
std::uint_fast8_t bitflag{ };
/* constexpr std::bitset<8> option1{ 0b0000'0000};
constexpr std::bitset<8> option2{ 0b0000'0001 };
constexpr std::bitset<8> option3{ 0b0000'0010 };
constexpr std::bitset<8> option4{ 0b0000'0100 };
constexpr std::bitset<8> option5{ 0b0000'1000 };
constexpr std::bitset<8> option6{ 0b0001'0000 };
constexpr std::bitset<8> option7{ 0b0010'0000 };
constexpr std::bitset<8> option8{ 0b0100'0000 };
std::bitset<8> bitflag{};*/ (this one can print out binary number)
bitflag |= option7;
std::cout << bitflag;
return 0;
}
When i had used uint_fast8_t, it had printed nothing. But, if i had used bitset, it had printed out the binary number. Can i known why it had been like that, what is my problem make it can not print out if i used uint_fast8_t (for the information, the compiler does not show any warning or error)
`std::uint_fast8_t` might be an `unsigned char`. `std::cout <<` treats `char` as characters. Add a cast to `int`.
when i used std::uint_fast16_t, it can print out 32. What should i do if i want to print out on binary (0010'0000), not on decimal (32)? If i used static_cast<int>(bitflag), it will going to print out decimal too. Should i make a function for let it print out binary number?
Either write a function to print binary or cast `bitflag` to a `std::bitset`.