Bity i C++

Opublikowane: 24/11/2014

w kategorii Zasoby.

Komputery przechowują informację używając bitów. Bit to najmniejsza porcja informacji - może mieć tylko wartość 0 lub 1. Operacje manipulacji bitami są użyteczne na najniższym poziomie programowania - kiedy operujesz na poziomie sprzętu. Mogą też być użyteczne do optymalizacji algorytmów ponieważ bit jest najmniejszą porcją danych.

Wbudowane operatory

Operatory przesunięcia bitowego "<<" (przesuń w lewo) oraz ">>" (przesuń w prawo) mogą być użyte do przesuwania bitów wartości.

Na przykład możesz:

unsigned a = 120;     // binarnie 01111000
unsigned b = a >> 2;  // binarnie 00011110
unsigned c = a << 1;  // binarnie 11110000

Operator AND ("i" / "&") może być użyty do wyłączenia części bitów w wartości, przykład:

unsigned a = 120;     // binarnie 01111000
unsigned b = 30;      // binarnie 00011110
// bitowy operator AND ('&'): tylko bity które są = '1' w obu argumentach są również = '1' w wyniku
unsigned c = a & b;   // binarnie 00011000

Operator OR (lub / "|") może być użyty do obliczenia bitów które są = '1' w którymkolwiek z argumentów

unsigned a = 120;     // binarnie 01111000
unsigned b = 30;      // binarnie 00011110
unsigned c = a & b;   // binarnie 01111110 = 126

Operator XOR (alternatywa wykluczająca / "^") może być użyty do odwrócenia niektórych bitów w pierwszym argumencie, tylko bity które są wyłącznie w jednym z argumentów = '1' pozostaną jako '1' w wyniku

unsigned a = 120;     // binarnie 01111000
unsigned b = 30;      // binarnie 00011110
unsigned c = a ^ b;   // binarnie 01100110 = 102

Operator NOT (negacja / "!") zmienia wszystkie bity na przeciwne, więc "1" stanie się "0" a "0" stanie się "1"

unsigned a = 120;     // binarnie 01111000
unsigned b = !a;      // binarnie 10000111 = 135

Zobacz także:

Literały bitowe

Literały bitowe w C++14

Począwszy od C++14 będzie można użyć wbudowanego wsparcia dla binarnych stałych jak w przykładzie:

int a = 0b01111000;

Zobacz:

Inne rozwiązania

Formatowanie

Możesz użyć następującej funkcji aby wydrukować wartość jako liczbę bitową:

#include <iostream>
#include <bitset>

using namespace std;

void pokaz_binarnie(unsigned short int value, unsigned int width) 
{ 
  unsigned int t = 1;
  if (width > 1) 
    t = t << (width - 1);   
  for(; t>0; t = t/2) 
    if(value & t) cout << '1'; 
    else cout << '0'; 
}

int main() {
  pokaz_binarnie(12, 16); // pokazuje 0000000000001100 
}

C++ ma również typ bitset który upraszcza pracę z bitami, ale wymaga deklaracji rozmiaru w trakcie kompilacji:

#include <iostream>
#include <bitset>

using namespace std;

void pokaz_binarnie(unsigned short int value) {
  bitset<16> bits(value);
  cout << bits;      
}

int main() {
  pokaz_binarnie(12); // pokazuje 0000000000001100 
}

Liczby całkowite znakowane

Liczby całkowite znakowane (np. int) pozwalają na przechowywanie wartości które są mniejsze od zera. Mogą one być przechowywane jako zwykłe liczby nieznakowane i interpretowane jako znakowane tam gdzie potrzeba ("kod uzupełnień do dwóch").

Aby to przetestować, przyjrzyj się następującemu przykładowi (zakładając że unsigned short ma 16 bitów):

#include <iostream>
#include <climits>
#include <bitset>
using namespace std;

void pokaz_binarnie(unsigned short int value) {
  bitset<16> bits(value);
  cout << bits;      
}

// sprawdź czy wartość jest < 0
bool is_negative_signed_emul(unsigned short int value) {
  static const unsigned short int mask = 1 << 15;
  return (value & mask); 
}

// odwroć znak wartości w trybie emulowanym
unsigned short int neg_signed_emul(unsigned short int value) {
    return (value ^ USHRT_MAX) + 1;
}

// pokaż liczbę znakowaną emulowaną w nieznakowanej
void show_signed_emul(unsigned short int value) {
  if (is_negative_signed_emul(value)) { 
    value = neg_signed_emul(value);
    cout << "-";      
  }  
  cout << value;      
}

int main() {
   unsigned short int a = 12;     // binarnie 1100
   unsigned short int b; 
   unsigned short int c;

   pokaz_binarnie(a);  
   cout << " = " << a << endl;

   b = 13;
   c = a - b;

   pokaz_binarnie(c);  
   cout << " = " << c << " = " << a << " - " << b << " = ";
   show_signed_emul(c);
   cout << endl;

   a = c;
   b = 2;
   c = a - b;
   pokaz_binarnie(c);  
   cout << " = " << c << " = " << a << " - " << b << " = ";
   show_signed_emul(c);
   cout << endl;

   a = c;
   b = 3;
   c = a + b;
   pokaz_binarnie(c);  
   cout << " = " << c << " = " << a << " + " << b << endl;

   a = c;
   b = 1;
   c = a + b;
   pokaz_binarnie(c);  
   cout << " = " << c << " = " << a << " + " << b << endl;

   a = c;
   c = neg_signed_emul(a); // zmień znak
   show_binary(c);  
   cout << " = " << c << " = NEG(" << a << ")" << " = ";

   show_signed_emul(c);
   cout << endl;
   return 0;
}

Wynik:

0000000000001100 = 12
1111111111111111 = 65535 = 12 - 13 = -1
1111111111111101 = 65533 = 65535 - 2 = -3
0000000000000000 = 0 = 65533 + 3
0000000000000001 = 1 = 0 + 1
1111111111111111 = 65535 = NEG(1) = -1

Zobacz również:

Kontenery bitowe

Jest kilka kontenerów które mogą przechowywać wartości typu bool. Zobacz listę poniżej:

1) std::vector - kontener zoptymalizowany pod względem zajętości pamięci, który nie przechowuje każdej wartości osobno przez co nie działa tak jak inne kontenery STL

Wady:

2) std::bitset - kontener bitowy o stałym rozmiarze, działa jak lepszy "unsigned int", wyspecjalizowany do operacji bitowych, rozmiar ograniczony tylko przez dostępną pamięć

3) boost::container::vector - kontener o zmiennym rozmiarze, gdzie każdy element przechowywany jest pod osobnym adresem

4) boost::dynamic_bitset - wersja kontenera std::bitset z rozmiarem wyspecyfikowanym w czasie uruchomienia programu

Triki bitowe

Inne zasoby

Udostępnij

obserwuj