Usa Bitmask in C++

Jinku Hu 12 ottobre 2023
  1. Usa struct per definire la maschera di bit e implementare l’oggetto data in C++
  2. Usa struct e union per definire la maschera di bit e implementare l’oggetto data in C++
  3. Usa std::bitset per definire la maschera di bit in C++
Usa Bitmask in C++

Questo articolo illustrerà più metodi su come utilizzare la maschera di bit in C++.

Usa struct per definire la maschera di bit e implementare l’oggetto data in C++

struct è una struttura dati popolare in C++. Inoltre, è solo leggermente diverso dalla class rispetto al linguaggio C. In questo caso, abbiamo solo bisogno di definire struct con diversi membri dati, ma c’è una nuova notazione : usata dopo ogni nome di variabile e un numero intero specificato. Come mostrato nel codice di esempio, abbiamo dichiarato una struct con membri di dati di tipo uint32_t e la somma dei numeri a destra è 32. Questa costruzione implica che la struct occupa la dimensione di un singolo uint32_t tipo di dati in memoria e l’utente può accedere ai suoi intervalli di bitfield (23:5:4) separatamente.

Questo metodo viene utilizzato principalmente per risparmiare l’utilizzo della memoria di strutture di dati che potrebbero essere compresse in strutture simili. È anche uno dei modi più comuni per accedere a dati più piccoli di un byte nel linguaggio di programmazione C++. Nota che il primo membro anno può contenere solo valori interi fino a 223-1 e gli altri membri seguono in modo simile.

#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;
}

Produzione:

sizeof Bitfield: 4 bytes
date: 13/12/2020

Usa struct e union per definire la maschera di bit e implementare l’oggetto data in C++

Il metodo precedente è un modo sufficiente e corretto per implementare la maschera di bit. Tuttavia, ha uno svantaggio: l’accesso e l’assegnazione di valori ai membri richiede relativamente più tempo rispetto alle operazioni sui tipi incorporati. Questo può essere risolto implementando un oggetto di tipo union costituito da una struct e da una singola variabile di tipo incorporata. Notare che struct è il layout è lo stesso che costruiremmo nel metodo precedente. In questo caso, la differenza è la variabile uint32_t ydm che occupa la stessa dimensione della struct.

L’idea è di inizializzare / assegnare ai membri dei dati i loro valori molto più velocemente. Vale a dire, costruiamo un intero con operazioni bit per bit che corrispondono esattamente alla disposizione dei bit quando sono memorizzati nella struct e poi lo assegniamo a un singolo membro uint32_t. Ciò consente di risparmiare tempo per accedere ai dati una volta anziché ripetere la stessa operazione per ciascuno dei tre membri.

L’aritmetica bit per bit è relativamente semplice; vale a dire, iniziamo con il valore del primo membro nella struct, che viene modificato in OR con il risultato del membro successivo spostato a sinistra del numero di bit occupati dal membro precedente, e segue in modo simile.

#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

Usa std::bitset per definire la maschera di bit in C++

std::bitset è una caratteristica della libreria standard che include la classe per memorizzare i dati della maschera binaria. bitset ha più utili funzioni di manipolazione integrate e la dichiarazione è abbastanza semplice. Può essere inizializzato con un valore di stringa binaria o più valori numerici. Le operazioni bit per bit sono metodi incorporati e possono essere chiamate con operatori tradizionali sovraccaricati. Notare che, il metodo reset modifica permanentemente il bitset da cui viene chiamato.

#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;
}

Produzione:

bs1        : 1100100011110010
bs2        : 1111111111110000
NOT bs1    : 0011011100001101
bs1 AND bs2: 1100100011110000
bs1 reset  : 0000000000000000
Autore: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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