Dlaczego logiczny 1 bajt, a nie 1 bit?


127

W C ++

  • Dlaczego logiczny 1 bajt, a nie 1 bit?
  • Dlaczego nie ma typów takich jak 4-bitowe lub 2-bitowe liczby całkowite?

Brakuje mi powyższych rzeczy podczas pisania emulatora dla procesora


10
W C ++ można „spakować” dane za pomocą pól bitowych. struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };. Większość kompilatorów przydzieli pełne unsigned int, jednak same radzą sobie z manipulowaniem bitami podczas odczytu / zapisu. Również samodzielnie radzą sobie z operacjami modulo. To znaczy, że unsigned small : 4atrybut ma wartość od 0 do 15, a kiedy powinien osiągnąć 16, nie nadpisze poprzedniego bitu :)
Matthieu M.

Odpowiedzi:


208

Ponieważ procesor nie może adresować niczego mniejszego niż bajt.


10
Cholera, teraz to niezręczne Sir
Asm,

31
Faktycznie, cztery instrukcje x86 bt, bts, btri btc może zająć pojedynczych bitów!
fredoverflow,

11
Myślę, że btadresuje przesunięcie bajtów, a następnie testuje bit przy danym przesunięciu, niezależnie od tego, kiedy określasz adres, który podajesz w bajtach ... literały bitowego przesunięcia byłyby nieco rozwlekłe (przepraszam za kalambur).
user7116,

2
@six: Możesz załadować początek tablicy w jednym rejestrze, a następnie względne „przesunięcie bitowe” w sekundę. Przesunięcie bitowe nie jest ograniczone do „jednego bajtu”, może to być dowolna liczba 32-bitowa.
fredoverflow,

4
Cóż, tak i nie. Mamy pola bitowe i moglibyśmy mieć wskaźnik pola bitowego, czyli adres + numer bitu. Oczywiście takiego wskaźnika nie można zamienić na void * ze względu na dodatkowe wymagania dotyczące przechowywania numeru bitu.
Maxim Egorushkin

32

Z Wikipedii :

Historycznie bajt był liczbą bitów użytych do zakodowania pojedynczego znaku tekstu w komputerze iz tego powodu jest podstawowym elementem adresowalnym w wielu architekturach komputerów.

Tak bajt jest Podstawową jednostką adresowalnych , poniżej którego architektura komputer nie adres. A ponieważ nie ma (prawdopodobnie) komputerów obsługujących 4-bitowe bajty, nie masz 4-bitowych itd. bool

Jeśli jednak potrafisz zaprojektować taką architekturę, która może adresować 4-bitową jednostkę adresowalną jako podstawową adresowalną jednostkę, wówczas będziesz mieć boolrozmiar 4-bitowy tylko na tym komputerze!


4
"będziesz miał wtedy int o rozmiarze 4-bitowym, tylko na tym komputerze" - nie, nie zrobisz tego, ponieważ standard zabrania CHAR_BIT, aby był mniejszy niż 8. Jeśli adresowalna jednostka w architekturze ma mniej niż 8 bitów, Implementacja C ++ będzie musiała po prostu przedstawić model pamięci, który różni się od modelu pamięci bazowego sprzętu.
Steve Jessop

@Steve: oops ... Przeoczyłem to. Usunięte intiz charmojego postu.
Nawaz,

1
nie możesz też mieć 4-bitowego bool, ponieważ charjest to najmniejsza adresowalna jednostka w C ++ , niezależnie od tego, co architektura może adresować za pomocą własnych kodów operacyjnych. sizeof(bool)musi mieć wartość co najmniej 1, a sąsiednie boolobiekty muszą mieć własne adresy w C ++ , więc implementacja musi tylko je powiększyć i marnować pamięć. Dlatego pola bitowe istnieją jako szczególny przypadek: elementy składowe bitfield struktury nie muszą być oddzielnie adresowalne, więc mogą być mniejsze niż a char(chociaż cała struktura nadal nie może być).
Steve Jessop

@ Steve Jessop: to wydaje się interesujące. czy mógłbyś mi podać odniesienie ze specyfikacji języka, w którym mówi się, że charjest to najmniejsza adresowalna jednostka w C ++?
Nawaz

3
najbliższe specyficzne stwierdzenie to prawdopodobnie 3.9 / 4: "Reprezentacja obiektowa obiektu typu T to sekwencja N obiektów typu unsigned char zajętych przez obiekt typu T, gdzie N równa się sizeof (T)". Oczywiście sizeof(bool)nie może to być 0.5 :-) Przypuszczam, że implementacja mogłaby legalnie dostarczać wskaźniki sub-bajtowe jako rozszerzenie, ale "zwykłe" obiekty, takie jak bool, przydzielone w zwykły sposób, muszą robić to, co mówi standard.
Steve Jessop

12

Najłatwiejsza odpowiedź brzmi; dzieje się tak dlatego, że procesor adresuje pamięć w bajtach, a nie w bitach, a operacje bitowe są bardzo wolne.

Jednak możliwe jest użycie alokacji rozmiaru bitowego w C ++. Istnieje specjalizacja std :: vector dla wektorów bitowych, a także struktury przyjmujące wpisy o rozmiarze bitowym.


1
Nie jestem pewien, czy zgodziłbym się, że operacje bitowe są powolne. ands, nots, xors itp. są bardzo szybkie. Zwykle implementacja operacji bitowych jest powolna. Na poziomie maszyny są dość szybkie. Rozgałęzianie ... teraz to jest powolne.
Hogan,

3
Dla jasności, jeśli utworzysz wektor wartości logicznych i wstawisz do niego 24 wartości logiczne, zajmie to tylko 3 bajty (3 * 8). Jeśli wstawisz inną wartość logiczną, zajmie to kolejny bajt. Jednak jeśli wepchniesz inny logiczny, nie zajmie to żadnych dodatkowych bajtów, ponieważ używa „wolnych” bitów w ostatnim bajcie
Pedro Loureiro,

tak, wątpię również, że operacje bitewise są powolne :)
Pedro Loureiro

Wektory bitowe nie tworzą alokacji o rozmiarze bitowym. tworzą alokacje wielkości bajtów. Nie można przydzielić ani jednego bitu.
John Dibling,

1
Odczyt pojedynczego bitu w wektorze bitowym wymaga trzech operacji: shift i i jeszcze raz kolejnego przesunięcia. Pisanie to dwa. Natomiast dostęp do poszczególnych bajtów można uzyskać za pomocą jednego.
sukru

7

W dawnych czasach, kiedy musiałem chodzić do szkoły w szalejącej zamieci, pod górę w obie strony, a obiad był jakimkolwiek zwierzęciem, które mogliśmy wytropić w lesie za szkołą i zabić gołymi rękami, komputery miały znacznie mniej dostępnej pamięci niż dzisiaj. Pierwszy komputer, z jakim korzystałem, miał 6 KB pamięci RAM. Nie 6 megabajtów, nie 6 gigabajtów, 6 kilobajtów. W tym środowisku bardzo sensowne było umieszczanie jak największej liczby wartości logicznych w int, więc regularnie korzystaliśmy z operacji, aby je usuwać i umieszczać.

Dzisiaj, gdy ludzie będą kpić z tego, że masz tylko 1 GB pamięci RAM, a jedynym miejscem, w którym można znaleźć dysk twardy o pojemności mniejszej niż 200 GB, jest antykwariat, po prostu nie warto pakować bitów.


Z wyjątkiem sytuacji, gdy mamy do czynienia z flagami. Rzeczy takie jak ustawienie wielu opcji czegoś ... np. 00000001 + 00000100 = 00000101.
Armstrongest

@Atomix: Prawie nigdy już tego nie robię. Jeśli potrzebuję dwóch flag, tworzę dwa pola logiczne. Kiedyś pisałem kod, w którym pakowałem flagi w ten sposób, a następnie pisałem „if flags & 0x110! = 0 then” lub podobne, ale to jest tajemnicze i obecnie generalnie tworzę oddzielne pola i piszę „if fooFlag || barFlag " zamiast. Nie wykluczałbym przypadków, w których takie pakowanie flag jest lepsze z jakiegoś powodu, ale nie jest już konieczne oszczędzanie pamięci, tak jak kiedyś.
Jay

2
Właściwie, to jest całkiem warta kłopoty spakować bitów, jeśli chcesz, aby obliczenia być szybki - na tej dużej ilości danych przechowywanych w pamięci. Pakowanie wartości logicznych nie jest przeznaczone tylko do mniejszego miejsca na dane - oznacza to, że możesz odczytywać tablice wejściowe wartości boolowskich 8 razy szybciej (pod względem przepustowości) niż podczas rozpakowywania, a to często jest dość znaczące. Możesz także używać operacji bitowych, takich jak popc (licznik populacji), co przyspiesza pracę na samym procesorze.
einpoklum

2
Naprawdę ogromna liczba wartości logicznych jest tym, z czym pracujesz każdego dnia: DBMS, uczenie maszynowe, symulacje naukowe i wiele innych rzeczy. I - sama praca nad nimi oznacza kopiowanie ich - z pamięci do pamięci podręcznej. Milion booli to nic, pomyśl miliardy.
einpoklum

1
@PeterCordes Tak, absolutnie, gdybym miał zestaw parametrów logicznych, które byłyby logicznie „tym samym pomysłem”, więc naturalnie myślę o nich w pewnym sensie jako o „tablicy”, a jeśli zamierzam je zamaskować lub przefiltrować lub w przeciwnym razie wykonuj na nich operacje bitowe, a następnie pakowanie ich do bajtów może mieć sens. Jak powiedziałem wcześniej, ciężko mi jest pomyśleć o ostatnim razem, kiedy pracowałem nad aplikacją, w której obowiązywały te warunki, ale podasz kilka dobrych przykładów i jestem pewien, że przy odrobinie wyobraźni można by pomyśleć o innych.
Jay

6

Możesz użyć pól bitowych, aby uzyskać liczby całkowite o rozmiarze podrzędnym.

struct X
{
    int   val:4;   // 4 bit int.
};

Chociaż jest zwykle używany do mapowania struktur do dokładnych oczekiwanych przez sprzęt wzorców bitów:

struct SomThing   // 1 byte value (on a system where 8 bits is a byte
{
    int   p1:4;   // 4 bit field
    int   p2:3;   // 3 bit field
    int   p3:1;   // 1 bit
};

6

Możesz mieć 1-bitowe boole oraz 4 i 2-bitowe liczby wewnętrzne. Ale to spowodowałoby dziwny zestaw instrukcji bez zwiększenia wydajności, ponieważ jest to nienaturalny sposób patrzenia na architekturę. W rzeczywistości sensowne jest „zmarnowanie” większej części bajtu, zamiast próbować odzyskać te nieużywane dane.

Z mojego doświadczenia wynika, że ​​jedyną aplikacją, która przeszkadza spakować kilka wartości logicznych w jeden bajt, jest Sql Server.


6

Ponieważ bajt to najmniejsza adresowalna jednostka w języku.

Ale możesz sprawić, by bool wziął 1 bit, na przykład, jeśli masz ich kilka, np. w strukturze, takiej jak ta:

struct A
{
  bool a:1, b:1, c:1, d:1, e:1;
};

2

boolmoże być jednym bajtem - najmniejszy adresowalny rozmiar procesora lub może być większy. Nie jest niczym niezwykłym, aby mieć boolrozmiar intdo celów wydajnościowych. Jeśli do określonych celów (np. Symulacja sprzętu) potrzebujesz typu z N bitami, możesz znaleźć bibliotekę do tego (np. Biblioteka GBL ma BitSet<N>klasę). Jeśli martwisz się rozmiarem bool(prawdopodobnie masz duży pojemnik,) możesz spakować bity samodzielnie lub użyć std::vector<bool>tego, który zrobi to za Ciebie (uważaj na ten drugi, ponieważ nie spełnia on wymagań pojemnika).


2

Pomyśl, jak zaimplementowałbyś to na poziomie emulatora ...

bool a[10] = {false};

bool &rbool = a[3];
bool *pbool = a + 3;

assert(pbool == &rbool);
rbool = true;
assert(*pbool);
*pbool = false;
assert(!rbool);

2

Ponieważ ogólnie procesor przydziela pamięć z 1 bajtem jako jednostką podstawową, chociaż niektóre procesory, takie jak MIPS, używają 4-bajtowego słowa.

Jednak vectorzajmuje się boolw specjalny sposób, z vector<bool>jednym bitem na każdy bool.


1
Wierzę, że nawet procesor MIPS da ci dostęp do pojedynczego bajtu, chociaż istnieje spadek wydajności.
Paul Tomblin,

@Paul: Tak, masz rację, ale generalnie te słowa lw/ swsą znacznie szerzej używane.
Ryan Li

Nie wiem o MIPS, ale architektura IA-64 umożliwia dostęp tylko na granicy 64-bitowej.
Gene Bushuyev,

0

Bajt to mniejsza jednostka przechowywania danych cyfrowych w komputerze. W komputerze pamięć RAM ma miliony bajtów i każdy z nich ma adres. Gdyby miał adres dla każdego bitu, komputer mógłby zarządzać 8 razy mniej pamięci RAM niż może.

Więcej informacji: Wikipedia


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.