How to Use Bitmask in C++
-
Use
struct
to Define Bitmask and Implement Date Object in C++ -
Use
struct
andunion
to Define Bitmask and Implement Date Object in C++ -
Use
std::bitset
to Define Bitmask in C++
This article will demonstrate multiple methods of how to use bitmask in C++.
Use struct
to Define Bitmask and Implement Date Object in C++
struct
is a popular data structure in C++. Moreover, it is only slightly different from the class
as opposed to the C language. In this case, we only need to define struct
with several data members, but there’s a new notation :
used after each variable name and an integer specified. As shown in the example code, we declared a struct
with uint32_t
type data members, and the sum of the numbers on the right is 32. This construction implies that the struct
occupies the size of a single uint32_t
data type in memory and the user can access its bitfield ranges(23:5:4) separately.
This method is mostly utilized to save memory utilization of data structures that might be squeezed into similar structs
. It’s also one of the common ways to access smaller data than a byte in C++ programming language. Note that the first member year
can only hold integer values up to 223-1 and other members follow similarly.
#include <iostream>
using std::cout;
using std::endl;
struct {
uint32_t year : 23;
uint32_t day : 5;
uint32_t month : 4;
} typedef Bitfield;
int main() {
Bitfield date = {2020, 13, 12};
cout << "sizeof Bitfield: " << sizeof(date) << " bytes\n";
cout << "date: " << date.day << "/" << date.month << "/" << date.year << endl;
return EXIT_SUCCESS;
}
Output:
sizeof Bitfield: 4 bytes
date: 13/12/2020
Use struct
and union
to Define Bitmask and Implement Date Object in C++
The previous method is a sufficient and correct way of implementing bitmask. Still, it has one downside - accessing and assigning values to members takes relatively more time than operations on built-in types. This can be solved by implementing a union
type object consisting of a struct
and a single built-in type variable. Note that, struct
is layout is the same as we would construct in the previous method. In this case, the difference is the variable uint32_t ydm
that occupies the same size as the struct
.
The idea is to initialize/assign data members their values much faster. Namely, we construct an integer with bitwise operations that exactly match the layout of bits when they are stored in the struct
and then assign it to a single uint32_t
member. This saves time to access data one time rather than repeat the same operation for each of three members.
Bitwise arithmetic is relatively straightforward; namely, we start with the first member’s value in the struct
, which is OR-ed with the result of the next member shifted left by the number of bits the previous member occupies, and it follows similarly.
#include <iostream>
using std::cout;
using std::endl;
union BitfieldFast {
struct {
uint32_t year : 23;
uint32_t day : 5;
uint32_t month : 4;
};
uint32_t ydm;
};
int main() {
BitfieldFast date_f{};
date_f.ydm = 2020 | (13 << 23) | (12 << 28);
cout << "sizeof BitfieldFast: " << sizeof(date_f) << " bytes\n";
cout << "date: " << date_f.day << "/" << date_f.month << "/" << date_f.year
<< endl;
return EXIT_SUCCESS;
}
sizeof BitfieldFast: 4 bytes
date: 13/12/2020
Use std::bitset
to Define Bitmask in C++
std::bitset
is a standard library feature that includes the class for storing the binary mask data. bitset
has multiple useful manipulation functions built-in, and declaration is quite effortless. It can be initialized with a binary string value or multiple number values. Bitwise operations are built-in methods and can be called with traditional operators that are overloaded. Notice that, reset
method permanently modifies the bitset
it’s called from.
#include <bitset>
#include <iostream>
using std::cout;
using std::endl;
int main() {
std::bitset<16> bs1("1100100011110010");
std::bitset<16> bs2(0xfff0);
cout << "bs1 : " << bs1 << endl;
cout << "bs2 : " << bs2 << endl;
cout << "NOT bs1 : " << ~bs1 << endl;
cout << "bs1 AND bs2: " << (bs1 & bs2) << endl;
cout << "bs1 reset : " << bs1.reset() << endl;
return EXIT_SUCCESS;
}
Output:
bs1 : 1100100011110010
bs2 : 1111111111110000
NOT bs1 : 0011011100001101
bs1 AND bs2: 1100100011110000
bs1 reset : 0000000000000000
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook