C ++: dlaczego bool ma 8 bitów?

133

W C ++ zastanawiam się, dlaczego typ bool ma długość 8 bitów (w moim systemie), gdzie tylko jeden bit wystarczy do przechowywania wartości boolowskiej?

Kiedyś sądziłem, że dzieje się tak ze względu na wydajność, ale na komputerze 32- lub 64-bitowym, gdzie rejestry mają szerokość 32 lub 64 bitów, jaka jest przewaga wydajności?

A może to tylko jeden z tych „historycznych” powodów?

Jérôme
źródło
10
W moim systemie wartość bool nie jest 8-bitowa. To 4 bajty, czyli tyle samo, co int.
Brian Neal
21
Ostatnim razem, gdy ktoś pomyślał o tym, co myślisz, skończyło się na std :: vector <bool>, najbardziej znienawidzonej funkcji STL kiedykolwiek =)
Viktor Sehr
1
jldupont, myślę, że mnie źle odczytałeś. sizeof(bool)Prosiłem o system, w którym byłby 4. Mógłbym przysiąc, że msvc ma 32-bitowe boole, ale po prostu próbowałem i tak nie jest.
avakar
7
Aby być uczciwym, problem vector<bool>nie polega na tym, że stara się być sprytny i pakować wartości logiczne w bity, ale próbuje to zrobić i ukryć się jako kontener STL . Zwykły zestaw bitów byłby dobry, o ile nie udaje kontenera STL.
jalf
2
@avakar - możesz pomylić booltyp danych C ++ z BOOLtypem systemu Windows, który jest zdefiniowany jako long. Tak więc sizeof(bool) != sizeof(BOOL), co na pewno powoduje wiele zamieszania (i prawdopodobnie sporo błędów). Zwłaszcza, że w systemie Windows są również booleani BOOLEANtypedefs, które są aliasami dla unsigned char. Zwróć również uwagę, że chociaż często booljest to 1 bajt, standard C ++ ma notatkę, która wyraźnie wskazuje, że sizeof(bool)może być większy.
Michael Burr

Odpowiedzi:

220

Ponieważ każdy typ danych C ++ musi być adresowalny.

Jak utworzyłbyś wskaźnik do pojedynczego bitu? Nie możesz. Ale można utworzyć wskaźnik do bajta. Tak więc wartość logiczna w C ++ ma zazwyczaj rozmiar bajtowy. (Może być również większy. To zależy od implementacji. Najważniejsze jest to, że musi być adresowalny, więc żaden typ danych w C ++ nie może być mniejszy niż bajt)

jalf
źródło
7
Adresowanie „bajtowe” jest wyborem architektonicznym (poziom hw): można bardzo dobrze zaprojektować system z inną „jednostką adresowania”. W przypadku typowych procesorów, adresowanie „bajtu” i tak kończy się pobraniem więcej niż „bajtu” z pamięci zewnętrznej: jest to spowodowane wydajnością.
jldupont
8
Tak, jest to wybór sprzętu, a jeśli sprzęt na to pozwala, rozmiar bool może się zmienić. Ale OP zapytał, dlaczego bool ma szerokość 8 bitów, a w systemach, w których tak jest, dzieje się tak zazwyczaj dlatego, że procesor jest w stanie adresować tylko 8-bitowe bajty.
jalf
2
@jldupont: Jest kilka systemów, w których adresy wskaźników są dokładniejsze niż bajty (wcześniej programowałem na starym TI TMS34010 / 20, który używa wskaźników bitowych), ale są one WYJĄTKOWO rzadkie.
Michael Kohne,
1
Nie wiem co masz na myśli. Każdy obiekt musi być adresowalny, to znaczy musi istnieć możliwość pobrania adresu obiektu. Obiekt nie musi przechowywać własnego adresu. Znak ma zazwyczaj szerokość 8 bitów, wystarczającą do przechowywania dowolnego z 256 znaków, ale każdy znak ma również adres określony przez miejsce w pamięci. Dlatego możesz utworzyć wskaźnik do znaku.
jalf
88
Jeśli mogę podać podejrzaną analogię: w moim budynku jest osiem pięter, ale Urząd Pocztowy nie przyznaje, że to różne adresy. Więc jeśli chcę mieć adres tylko dla siebie, to muszę wynająć cały budynek, mimo że faktycznie mieszczę się na jednym piętrze. Nie używam pozostałych siedmiu pięter do „przechowywania adresu”, jestem po prostu zmuszony do ich zmarnowania z powodu zasady Urzędu Pocztowego, że adresy odnoszą się do budynków, a nie pięter. Obiekty C ++ muszą mieć własny adres - brak pokojów pocztowych do sortowania poczty po dostarczeniu ;-)
Steve Jessop
39

Pamięć jest adresowalna bajtowo. Nie można zaadresować pojedynczego bitu bez przesuwania lub maskowania bajtu odczytanego z pamięci. Myślę, że to bardzo duży powód.

Stephen Roantree
źródło
1
Nie zawsze. Na przykład 8051 MCU ma 16 bajtów adresowalnych lokalizacji
Beached
20

booleanTypu normalnie następuje najmniejszą jednostkę adresowalnych pamięci urządzenia docelowego (to znaczy zwykle bajtów 8 bitów).

Dostęp do pamięci jest zawsze w „porcjach” (wiele słów, dotyczy to wydajności na poziomie sprzętowym , transakcji magistrali): bit boolowski nie może być adresowany „samodzielnie” w większości systemów CPU. Oczywiście, gdy dane są zawarte w rejestrze , często pojawiają się wyspecjalizowane instrukcje dotyczące niezależnego manipulowania bitami.

Z tego powodu dość powszechne jest stosowanie technik „pakowania bitów” w celu zwiększenia wydajności używania „logicznych” podstawowych typów danych. Technika taka jak enum(w C) z potęgą kodowania 2 jest dobrym przykładem. Ten sam rodzaj sztuczki można znaleźć w większości języków.

Zaktualizowano : Dzięki doskonałej dyskusji zwróciłem uwagę, że sizeof(char)==1z definicji w C ++. W związku z tym adresowanie „logicznego” typu danych jest dość powiązane z najmniejszą jednostką adresowalnej pamięci (wzmacnia mój punkt widzenia).

jldupont
źródło
Biorąc pod uwagę wszystkie komentarze, które na ten temat zostawiłeś, imponujące jest to, że pominąłeś najważniejszą część odpowiedzi: booltyp następuje po najmniejszej jednostce przydzielanej pamięci, ponieważ C ++ wymaga, aby było możliwe utworzenie do niego wskaźników . Bez tego wymogu, boolmożna by sobie wyobrazić, że byłby reprezentowany jako pojedynczy bit nawet na obecnych maszynach adresowanych bajtami.
jalf
1
hmmm ... Mógłbym stworzyć architekturę procesora, w której trochę mógłby być adresowalny ... Mógłbym nawet napisać dla niej kompilator itp. Mógłbym mieć specjalny obszar pamięci (lub cokolwiek), który byłby „adresowalny bitowo”. W żadnym wypadku nie jest to niemożliwe.
jldupont
2
Tak, i w tym systemie można by ustawić bool jako pojedynczy bit. Ale OP nie zapytał "dlaczego bool 8-bitowy jest szeroki na hipotetycznym procesorze jlduponts". Zapytał o obecne, powszechne, codzienne procesory, a to dlatego, że są adresowalne bajtami.
jalf
4
sizeof (char) == 1 na definicję w C ++, więc to, co twój sprzęt może, a czego nie może zrobić, nie jest istotne. Nie możesz mieć sizeof (bool) <sizeof (char). BTW C ++ jest zdefiniowane w taki sposób, że możesz mieć „gruby” wskaźnik do adresowania jakiejś podjednostki tego, co sprzęt może adresować, jeśli nie jest wygodnie mieć char najmniejszej sprzętowej adresowalnej jednostki. Było to używane przynajmniej w niektórych kompilatorach C dla architektur adresowalnych starych słów.
AProgrammer
@AProgrammer:: sizeof(char)==1 definitionto najlepszy kontrargument do mojej argumentacji. Dzięki!
jldupont
6

Odpowiedzi, że 8-bitów to najmniejsza ilość pamięci, która jest adresowalna, są poprawne. Jednak niektóre języki mogą w pewnym sensie używać 1-bitowych wartości logicznych. Wydaje mi się, że Pascal implementował zestawy jako ciągi bitów. To znaczy dla następującego zestawu:

{1, 2, 5, 7}

Możesz mieć to w pamięci:

01100101

Jeśli chcesz, możesz oczywiście zrobić coś podobnego w C / C ++. (Jeśli śledzisz kilka wartości logicznych, może to mieć sens, ale tak naprawdę zależy od sytuacji).

Benjamin Oakes
źródło
8
W rzeczywistości C ++ robi to za pomocą wyspecjalizowanego wektora kontenera <bool> - jest to powszechnie postrzegane jako katastrofa.
C ++ robi to również z „polami bitowymi”, dziedziczonymi po C. Deklarując zmienną składową struktury / klasy, możesz zadeklarować liczbę bitów używanych do przechowywania wartości (np. „Unsigned short field: 3”).
@Neil: dlaczego jest to powszechnie postrzegane jako katastrofa? Czy to problem z wydajnością?
Jérôme
2
@Jerome: To dlatego, że ponieważ bit nie jest adresowalny, nie może zachowywać się tak jak zwykły vector. W rzeczywistości nie jest to kontener typu STL, ponieważ istnieją ograniczenia dotyczące zachowania. Co gorsza, powoduje to problemy, gdy ktoś ma boolsi i chce je zrobić vector. To zaskakujące zachowanie, a nie tego chcesz w języku.
David Thornley,
1
@jldupont - wystarczy raz coś takiego zrobić. A C ++ nie gwarantuje, że bity są adresowalne (raczej odwrotnie), bez względu na to, do czego zdolny jest sprzęt.
1

Wiem, że to jest stare, ale pomyślałem, że dorzucę moje 2 centy.

Jeśli ograniczysz wartość logiczną lub typ danych do jednego bitu, Twoja aplikacja będzie narażona na uszkodzenie pamięci. Jak radzisz sobie ze statystykami błędów w pamięci, która ma tylko jeden bit?

Poszedłem na rozmowę kwalifikacyjną i jedno ze stwierdzeń, które kierownik programu powiedział mi, brzmiało: „Kiedy wysyłamy sygnał do wystrzelenia pocisku, po prostu wysyłamy prosty, jeden bit przez sieć bezprzewodową. potrzebuję tego sygnału, aby był jak najszybszy ”.

Cóż, był to test, aby sprawdzić, czy rozumiem pojęcia i bity, bajty i obsługa błędów. Jak łatwo byłoby złemu facetowi wysłać krótką wiadomość. Albo co się stanie, jeśli podczas transmisji bit zostanie odwrócony w drugą stronę.

Cire
źródło
Zadaj nowe pytanie , nie publikuj swojego pytania jako odpowiedzi na inne pytania.
Igor Jerosimić
6
Myślę, że pytanie zawarte w tej „odpowiedzi” jest w rzeczywistości pytaniem retorycznym, tj. Powodem, dla którego nie implementujemy wartości logicznych jako jednego bitu, jest to, że pojedynczy bit nie obsługuje statystyk błędów.
Stephen Holt
1
@StephenHolt, ale to nie jest powód i TBH ta odpowiedź nie ma żadnego sensu.
doc
1
...co? Nie wiem, co masz na myśli przez „statystyki błędów”, czy to CRC lub tym podobne, czy też reprezentacje pułapek. Ale w każdym razie nawet większe typy nie używają swoich dodatkowych, „zapasowych” bitów do „statystyk błędów”, ponieważ wszyscy programiści z wyjątkiem ekstremalnych środowisk słusznie zakładają, że ich sprzęt może obsługiwać wykrywanie / korygowanie błędów, zanim ich kod kiedykolwiek odczyta pamięć, więc nie muszą spędzać czasu na wypełnianiu każdej zmiennej informacjami weryfikacyjnymi lub czymkolwiek. Nie dlatego boolużywa 8 bitów na maszynie OP i 32 na mojej, ponieważ te pozostałe 7 lub 31 bitów z pewnością nie są używane do żadnych „statystyk błędów”. To nie ma sensu
podkreślenie_d
1

Niektóre wbudowane kompilatory mają typ int1, który jest używany do pakowania bitowych flag logicznych (np. Kompilatory C serii CCS dla mikrochipów MPU). Ustawianie, czyszczenie i testowanie tych zmiennych wykorzystuje instrukcje na poziomie bitów składające się z jednej instrukcji, ale kompilator nie zezwoli na żadne inne operacje (np. Pobranie adresu zmiennej) z powodów wymienionych w innych odpowiedziach.

EBlake
źródło