Warum ist ein Boolescher Wert 1 Byte und nicht 1 Bit groß?


127

In C ++

  • Warum ist ein Boolescher Wert 1 Byte und nicht 1 Bit groß?
  • Warum gibt es keine Typen wie 4-Bit- oder 2-Bit-Ganzzahlen?

Ich verpasse die oben genannten Dinge, wenn ich einen Emulator für eine CPU schreibe


10
In C ++ können Sie die Daten mithilfe von Bitfeldern "packen". struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };. Die meisten Compiler weisen eine vollständige Zuweisung zu unsigned int, sie kümmern sich jedoch selbst um das Bit-Twiddling, wenn Sie lesen / schreiben. Sie beschäftigen sich auch selbst mit den Modulo-Operationen. Das ist ein unsigned small : 4Attribut hat einen Wert zwischen 0 und 15, und wenn es auf 16 kommen sollte, wird das vorhergehende Bit nicht überschrieben :)
Matthieu M.

Antworten:


208

Weil die CPU nichts kleiner als ein Byte adressieren kann.


10
Verdammt, das ist unangenehm, Sir
Asm

31
Eigentlich sind die vier x86 - Befehle bt, bts, btrund btc können einzelne Bits adressieren!
Fredoverflow

11
Ich denke, btadressiert einen Byte-Offset und testet dann das Bit an einem bestimmten Offset, unabhängig davon, ob Sie eine Adresse in Bytes angeben ... Bit-Offset-Literale würden etwas wortreich werden (entschuldigen Sie das Wortspiel).
user7116

2
@six: Sie können den Anfang eines Arrays in ein Register und dann den relativen "Bitoffset" in ein zweites laden. Der Bitversatz ist nicht auf "innerhalb eines Bytes" beschränkt, sondern kann eine beliebige 32-Bit-Zahl sein.
Fredoverflow

4
Ja und nein. Wir haben Bitfelder, und wir könnten einen Bitfeldzeiger haben, das heißt Adresse + Bitnummer. Offensichtlich wäre ein solcher Zeiger aufgrund des zusätzlichen Speicherbedarfs für die Bitnummer nicht in void * konvertierbar.
Maxim Egorushkin

32

Aus Wikipedia :

In der Vergangenheit war ein Byte die Anzahl der Bits, die zum Codieren eines einzelnen Textzeichens in einem Computer verwendet wurden, und ist aus diesem Grund das grundlegende adressierbare Element in vielen Computerarchitekturen.

Byte ist also die grundlegende adressierbare Einheit , unterhalb derer die Computerarchitektur nicht adressieren kann. Und da es (wahrscheinlich) keine Computer gibt, die 4-Bit-Byte unterstützen, haben Sie kein 4-Bit bool usw.

Wenn Sie jedoch eine solche Architektur entwerfen können, die 4-Bit als adressierbare Grundeinheit adressieren kann, haben Sie booldann nur auf diesem Computer die Größe 4-Bit!


4
"Sie haben dann int der Größe 4-Bit, nur auf diesem Computer" - nein, das werden Sie nicht, da der Standard verbietet, dass CHAR_BIT kleiner als 8 ist. Wenn die adressierbare Einheit in der Architektur weniger als 8 Bit beträgt, dann a Die C ++ - Implementierung muss lediglich ein Speichermodell präsentieren, das sich vom Speichermodell der zugrunde liegenden Hardware unterscheidet.
Steve Jessop

@Steve: Ups ... das habe ich übersehen. Entfernt intund charvon meinem Beitrag.
Nawaz

1
Sie können auch kein 4-Bit haben bool, da dies die charkleinste adressierbare Einheit in C ++ ist , unabhängig davon, was die Architektur mit ihren eigenen Opcodes adressieren kann. sizeof(bool)muss einen Wert von mindestens 1 haben und benachbarte boolObjekte müssen ihre eigenen Adressen in C ++ haben , so dass die Implementierung sie nur größer machen und Speicher verschwenden muss. Aus diesem Grund gibt es als Sonderfall Bitfelder: Die Bitfeldelemente einer Struktur müssen nicht separat adressierbar sein, daher können sie kleiner als a sein char(obwohl die gesamte Struktur immer noch nicht sein kann).
Steve Jessop

@ Steve Jessop: das scheint interessant. Könnten Sie mir bitte die Referenz aus der Sprachspezifikation geben, in der steht, dass chares sich um die kleinste adressierbare Einheit in C ++ handelt?
Nawaz

3
Die nächste spezifische Aussage ist wahrscheinlich 3.9 / 4: "Die Objektdarstellung eines Objekts vom Typ T ist die Folge von N vorzeichenlosen Zeichenobjekten, die vom Objekt vom Typ T aufgenommen werden, wobei N gleich sizeof (T) ist." Offensichtlich sizeof(bool)kann nicht 0,5 sein :-) Ich nehme an, eine Implementierung könnte legal Sub-Byte-Zeiger als Erweiterung bereitstellen, aber "gewöhnliche" Objekte wie bool, die auf gewöhnliche Weise zugewiesen werden, müssen das tun, was der Standard sagt.
Steve Jessop

12

Die einfachste Antwort ist; Dies liegt daran, dass die CPU den Speicher in Bytes und nicht in Bits adressiert und die bitweisen Operationen sehr langsam sind.

Es ist jedoch möglich, die Bitgrößenzuweisung in C ++ zu verwenden. Es gibt eine std :: vector-Spezialisierung für Bitvektoren und auch Strukturen, die Einträge in Bitgröße verwenden.


1
Ich bin mir nicht sicher, ob ich zustimmen würde, dass bitweise Operationen langsam sind. ands, nots, xors usw. sind sehr schnell. Es ist typischerweise die Implementierung der bitweisen Operationen, die langsam sind. Auf Maschinenebene sind sie ziemlich schnell. Verzweigen ... jetzt ist das langsam.
Hogan

3
Um es klarer zu machen: Wenn Sie einen Vektor von Booleschen Werten erstellen und 24 Boolesche Werte darin einfügen, werden nur 3 Bytes (3 * 8) benötigt. Wenn Sie einen anderen Booleschen Wert eingeben, wird ein weiteres Byte benötigt. Wenn Sie jedoch einen anderen Booleschen Wert drücken, werden keine zusätzlichen Bytes benötigt, da die "freien" Bits im letzten Byte verwendet werden
Pedro Loureiro

Ja, ich bezweifle auch, dass bitweise Operationen langsam sind :)
Pedro Loureiro

Die Bitvektoren erzeugen keine Zuordnungen in Bitgröße. Sie erstellen Zuordnungen in Byte-Größe. Es ist nicht möglich, ein einzelnes Bit zuzuweisen.
John Dibling

1
Das Lesen eines einzelnen Bits in einem Bitvektor erfordert drei Operationen: Shift und und eine weitere Verschiebung. Schreiben ist zwei. Während auf einzelne Bytes mit einem einzigen zugegriffen werden kann.
Sukru

7

Früher, als ich in einem wütenden Schneesturm bergauf zur Schule gehen musste und das Mittagessen das Tier war, das wir im Wald hinter der Schule ausfindig machen und mit bloßen Händen töten konnten, hatten Computer viel weniger Speicher zur Verfügung als heute. Der erste Computer, den ich jemals benutzt habe, hatte 6 KB RAM. Nicht 6 Megabyte, nicht 6 Gigabyte, 6 Kilobyte. In dieser Umgebung war es sehr sinnvoll, so viele Boolesche Werte wie möglich in ein int zu packen. Daher verwendeten wir regelmäßig Operationen, um sie herauszunehmen und einzufügen.

Wenn Sie heute verspottet werden, nur 1 GB RAM zu haben, und der einzige Ort, an dem Sie eine Festplatte mit weniger als 200 GB finden könnten, ein Antiquitätengeschäft ist, lohnt es sich einfach nicht, Bits zu packen.


Außer beim Umgang mit Flaggen. Dinge wie das Festlegen mehrerer Optionen für etwas ... z. 00000001 + 00000100 = 00000101.
Armstrongest

@Atomix: Ich mache das fast nie mehr. Wenn ich zwei Flags benötige, erstelle ich zwei boolesche Felder. Früher habe ich Code geschrieben, in den ich solche Flags gepackt und dann "if flags & 0x110! = 0 then" oder ähnliches geschrieben habe, aber das ist kryptisch, und heutzutage mache ich im Allgemeinen separate Felder und schreibe "if fooFlag || barFlag" " stattdessen. Ich würde die Möglichkeit von Fällen nicht ausschließen, in denen das Packen solcher Flaggen aus irgendeinem Grund besser ist, aber es ist nicht mehr erforderlich, Speicher wie früher zu speichern.
Jay

2
Eigentlich ist es ganz wert Ihre Mühe Bits zu packen, wenn Sie Ihre Berechnung wollen schnell sein - auf dieser großen Menge an Daten , die Sie im Speicher ablegen. Das Packen von Booleschen Werten ist nicht nur für kleineren Speicher gedacht - es bedeutet, dass Sie Ihre booleschen Eingabearrays 8-mal schneller (in Bezug auf die Bandbreite) lesen können, als wenn sie entpackt sind, und das ist oft sehr wichtig. Sie können auch Bitoperationen wie popc (Populationsanzahl) verwenden, die Ihre Arbeit an der CPU selbst beschleunigen.
Einpoklum

2
Wenn Sie dies tun, arbeiten Sie jeden Tag mit einer wirklich großen Anzahl von Booleschen Werten: DBMS, maschinelles Lernen, wissenschaftliche Simulationen und eine ganze Reihe anderer Dinge. Und - nur daran zu arbeiten bedeutet, sie zu kopieren - aus dem Speicher in den Cache. Eine Million Bools ist nichts, denken Sie an Milliarden.
Einpoklum

1
@PeterCordes Ja, absolut, wenn ich eine Reihe von Booleschen Werten hätte, die logischerweise die "gleiche Idee" waren, so dass ich sie natürlich in gewissem Sinne als "Array" betrachte, und wenn ich sie dann maskieren oder filtern werde oder Andernfalls führen Sie bitweise Operationen an ihnen durch, und das Packen in Bytes ist möglicherweise sinnvoll. Wie ich bereits sagte, fällt es mir schwer, an das letzte Mal zu denken, als ich an einer Anwendung gearbeitet habe, bei der diese Bedingungen zutrafen, aber Sie geben ein paar gute Beispiele, und ich bin sicher, mit ein wenig Fantasie könnte man an andere denken.
Jay

6

Sie könnten 1-Bit-Bools und 4- und 2-Bit-Ints haben. Dies würde jedoch zu einem seltsamen Befehlssatz ohne Leistungsgewinn führen, da dies eine unnatürliche Art ist, die Architektur zu betrachten. Es ist tatsächlich sinnvoll, einen größeren Teil eines Bytes zu "verschwenden", anstatt zu versuchen, diese nicht verwendeten Daten zurückzugewinnen.

Die einzige App, die meiner Erfahrung nach mehrere Bools in ein einziges Byte packt, ist SQL Server.


5

Sie können Bitfelder verwenden, um Ganzzahlen mit Untergröße abzurufen.

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

Obwohl es normalerweise verwendet wird, um Strukturen exakten Hardware-erwarteten Bitmustern zuzuordnen:

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

5

Weil ein Byte die kleinste adressierbare Einheit in der Sprache ist.

Aber Sie können Bool zum Beispiel 1 Bit nehmen lassen, wenn Sie ein paar davon haben, z. in einer Struktur wie dieser:

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

2

boolkann ein Byte sein - die kleinste adressierbare Größe der CPU oder kann größer sein. Es ist nicht ungewöhnlich, dass Sie für Leistungszwecke booldie Größe haben müssen int. Wenn Sie für bestimmte Zwecke (z. B. Hardware-Simulation) einen Typ mit N Bits benötigen, können Sie eine Bibliothek dafür finden (z. B. hat die GBL-Bibliothek eine BitSet<N>Klasse). Wenn Sie sich mit der Größe von befassen bool(Sie haben wahrscheinlich einen großen Behälter), können Sie Bits selbst verpacken oder verwenden std::vector<bool>, um dies für Sie zu tun (seien Sie vorsichtig mit letzterem, da es die Behälteranforderungen nicht erfüllt).


2

Überlegen Sie, wie Sie dies auf Emulatorebene implementieren würden ...

bool a[10] = {false};

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

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

2

Da die CPU im Allgemeinen Speicher mit 1 Byte als Basiseinheit zuweist, verwenden einige CPUs wie MIPS ein 4-Byte-Wort.

Allerdings vectorbefasst sich boolin einer besonderen Art und Weise, mit vector<bool>einem Bit für jeden Bool zugeordnet ist.


1
Ich glaube, sogar die MIPS-CPU gibt Ihnen Zugriff auf ein einzelnes Byte, obwohl es eine Leistungsbeeinträchtigung gibt.
Paul Tomblin

@ Paul: Ja, Sie haben Recht, aber im Allgemeinen werden die wortspezifischen lw/ swviel häufiger verwendet.
Ryan Li

Ich weiß nichts über MIPS, aber die IA-64-Architektur erlaubt nur den Zugriff auf die 64-Bit-Grenze.
Gene Bushuyev

0

Das Byte ist die kleinere Einheit der digitalen Datenspeicherung eines Computers. In einem Computer hat der RAM Millionen von Bytes und jeder von ihnen hat eine Adresse. Wenn es eine Adresse für jedes Bit geben würde, könnte ein Computer 8 Mal weniger RAM verwalten als er kann.

Weitere Infos: Wikipedia


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.