Usar bitmask em C++
-
Utilizar
struct
para definir bitmask e implementar objecto de data em C++ -
Utilizar
struct
eunion
para definir bitmask e implementar objecto de data em C++ -
Utilize
std::bitset
para definir bitmask em C++
Este artigo irá demonstrar múltiplos métodos de como utilizar a bitmask em C++.
Utilizar struct
para definir bitmask e implementar objecto de data em C++
O struct
é uma estrutura de dados popular em C++. Além disso, é apenas ligeiramente diferente da class
em oposição à língua C. Neste caso, só precisamos de definir struct
com vários membros de dados, mas há uma nova notação :
utilizada após cada nome de variável e um número inteiro especificado. Como mostrado no código do exemplo, declaramos um struct
com membros de dados do tipo uint32_t
, e a soma dos números à direita é 32. Esta construção implica que o struct
ocupa o tamanho de um único tipo de dados uint32_t
na memória e o utilizador pode aceder aos seus intervalos de campo de bits(23:5:4) separadamente.
Este método é principalmente utilizado para guardar a utilização da memória de estruturas de dados que possam ser espremidas em struct
semelhantes. É também uma das formas comuns de aceder a dados mais pequenos que um byte em linguagem de programação C++. Note-se que o primeiro membro year
só pode conter valores inteiros até 223-1 e outros membros seguem de forma semelhante.
#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;
}
Resultado:
sizeof Bitfield: 4 bytes
date: 13/12/2020
Utilizar struct
e union
para definir bitmask e implementar objecto de data em C++
O método anterior é uma forma suficiente e correcta de implementar a bitmask. Ainda assim, tem um lado negativo - aceder e atribuir valores aos membros leva relativamente mais tempo do que as operações em tipos incorporados. Isto pode ser resolvido através da implementação de um objecto do tipo union
, que consiste num struct
e numa única variável do tipo incorporado. Note-se que, o struct
é a mesma disposição que construíríamos no método anterior. Neste caso, a diferença é a variável uint32_t ydm
que ocupa o mesmo tamanho que o struct
.
A ideia é inicializar/atribuir os seus valores aos membros dos dados muito mais rapidamente. Nomeadamente, construímos um inteiro com operações bitwise que correspondem exactamente à disposição dos bits quando estes são armazenados no struct
e depois atribuímos a um único membro uint32_t
. Isto poupa tempo para aceder aos dados uma vez em vez de repetir a mesma operação para cada um de três membros.
A aritmética bitwise é relativamente simples; nomeadamente, começamos com o valor do primeiro membro no struct
, que é OR-ed com o resultado do membro seguinte deslocado para a esquerda pelo número de bits que o membro anterior ocupa, e segue-se de forma semelhante.
#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
Utilize std::bitset
para definir bitmask em C++
std::bitset
é uma característica padrão da biblioteca que inclui a classe para armazenar os dados da máscara binária. O bitset
tem múltiplas funções de manipulação úteis incorporadas, e a declaração é bastante sem esforço. Pode ser inicializada com um valor binário string
ou valores de múltiplos números. As operações bitwise são métodos incorporados e podem ser chamadas com operadores tradicionais que estão sobrecarregados. Note-se que o método reset
modifica permanentemente o bitset
a partir do qual é chamado.
#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;
}
Resultado:
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