Perché un booleano ha 1 byte e non 1 bit di dimensione?


127

In C ++,

  • Perché un booleano ha 1 byte e non 1 bit di dimensione?
  • Perché non ci sono tipi come interi a 4 bit o 2 bit?

Sto perdendo le cose di cui sopra quando scrivo un emulatore per una CPU


10
In C ++ puoi "impacchettare" i dati utilizzando campi di bit. struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };. La maggior parte dei compilatori assegnerà un full unsigned int, tuttavia si occupano da soli dei bit-twiddling quando leggi / scrivi. Inoltre si occupano da soli delle operazioni modulo. Questo è un unsigned small : 4attributo che ha un valore compreso tra 0 e 15, e quando dovrebbe arrivare a 16, non sovrascriverà il bit precedente :)
Matthieu M.

Risposte:


208

Perché la CPU non può indirizzare nulla di più piccolo di un byte.


10
Dannazione, ora che è imbarazzante Sir
Asm

31
In realtà, i quattro x86 istruzioni bt, bts, btre btc possono indirizzare singoli bit!
fredoverflow

11
Penso che btindirizzi un offset di byte e quindi testa il bit a un dato offset, indipendentemente, quando si specifica un indirizzo si va in byte ... i valori letterali di offset dei bit diventerebbero un po 'prolissi (scusate il gioco di parole).
user7116

2
@six: è possibile caricare l'inizio di un array in un registro e quindi il relativo "bit offset" in un secondo. L'offset di bit non è limitato a "entro un byte", può essere qualsiasi numero di 32 bit.
fredoverflow

4
Ebbene sì e no. Abbiamo bitfield e potremmo avere un puntatore bitfield, che è indirizzo + numero di bit. Ovviamente, un tale puntatore non sarebbe convertibile in void * a causa del requisito di memoria aggiuntivo per il numero di bit.
Maxim Egorushkin

32

Da Wikipedia :

Storicamente, un byte era il numero di bit utilizzati per codificare un singolo carattere di testo in un computer ed è per questo motivo l'elemento indirizzabile di base in molte architetture di computer.

Quindi il byte è l' unità indirizzabile di base , al di sotto della quale l'architettura del computer non può indirizzarsi. E poiché (probabilmente) non esistono computer che supportano byte a 4 bit, non hai 4 bit bool ecc.

Tuttavia, se puoi progettare un'architettura di questo tipo che può indirizzare 4 bit come unità indirizzabile di base, allora avrai una booldimensione di 4 bit solo su quel computer!


4
"allora avrai int di dimensione 4 bit, solo su quel computer" - no non lo farai, perché lo standard impedisce a CHAR_BIT di essere inferiore a 8. Se l'unità indirizzabile sull'architettura è inferiore a 8 bit, allora un L'implementazione C ++ dovrà solo presentare un modello di memoria diverso dal modello di memoria dell'hardware sottostante.
Steve Jessop

@ Steve: oops ... l'ho trascurato. Rimosso inte chardal mio post.
Nawaz

1
non puoi nemmeno avere un 4 bit bool, perché charè la più piccola unità indirizzabile in C ++ , indipendentemente da ciò che l'architettura può affrontare con i propri codici operativi. sizeof(bool)deve avere un valore di almeno 1 e gli boologgetti adiacenti devono avere i propri indirizzi in C ++ , quindi l'implementazione deve solo renderli più grandi e sprecare memoria. Ecco perché i campi di bit esistono come un caso speciale: i membri del campo di bit di una struttura non devono essere indirizzati separatamente, quindi possono essere più piccoli di a char(sebbene l'intera struttura non possa ancora esserlo).
Steve Jessop

@ Steve Jessop: sembra interessante. potresti per favore darmi il riferimento dalla specifica del linguaggio dove si dice che charè la più piccola unità indirizzabile in C ++?
Nawaz

3
L'istruzione specifica più vicina è probabilmente 3.9 / 4: "La rappresentazione dell'oggetto di un oggetto di tipo T è la sequenza di N oggetti char senza segno occupata dall'oggetto di tipo T, dove N è uguale a sizeof (T)". Ovviamente sizeof(bool)non può essere 0,5 :-) Suppongo che un'implementazione possa fornire legalmente puntatori a subbyte come estensione, ma oggetti "ordinari" come bool, allocati in modi ordinari, devono fare ciò che dice lo standard.
Steve Jessop

12

La risposta più semplice è; è perché la CPU indirizza la memoria in byte e non in bit, e le operazioni bit per bit sono molto lente.

Tuttavia è possibile utilizzare l'allocazione della dimensione dei bit in C ++. C'è la specializzazione std :: vector per i vettori di bit e anche le strutture che accettano voci di dimensioni di bit.


1
Non sono sicuro di essere d'accordo sul fatto che le operazioni bit per bit siano lente. ands, nots, xors ecc sono molto veloci. Tipicamente è l'implementazione delle operazioni bit per bit che sono lente. A livello di macchina sono abbastanza veloci. Ramificazione ... ora che è lento.
Hogan

3
Solo per renderlo più chiaro, se crei un vettore di booleani e ci metti 24 booleani, ci vorranno solo 3 byte (3 * 8). Se inserisci un altro booleano, ci vorrà un altro byte. Tuttavia, se spingi un altro booleano, non ci vorranno byte extra perché utilizza i bit "liberi" nell'ultimo byte
Pedro Loureiro

sì, dubito anche che le operazioni di morso siano lente :)
Pedro Loureiro

I vettori di bit non creano allocazioni di dimensioni di bit. creano allocazioni di dimensioni di byte. Non è possibile allocare un singolo bit.
John Dibling

1
La lettura di un singolo bit in un vettore di bit richiede tre operazioni: shift e, e ancora un altro shift. La scrittura è due. Mentre è possibile accedere ai singoli byte con uno solo.
sukru

7

Ai vecchi tempi, quando dovevo andare a scuola a piedi in una violenta tormenta, in salita in entrambe le direzioni, e il pranzo era qualsiasi animale che potessimo rintracciare nei boschi dietro la scuola e uccidere a mani nude, i computer avevano molta meno memoria disponibile di oggi. Il primo computer che ho mai usato aveva 6K di RAM. Non 6 megabyte, non 6 gigabyte, 6 kilobyte. In quell'ambiente, aveva molto senso impacchettare quanti più booleani possibile in un int, quindi usavamo regolarmente le operazioni per estrarli e inserirli.

Oggi, quando le persone ti derideranno per avere solo 1 GB di RAM, e l'unico posto in cui potresti trovare un disco rigido con meno di 200 GB è un negozio di antiquariato, non vale la pena mettere in valigia i bit.


Tranne quando si tratta di Flags. Cose come impostare più opzioni su qualcosa ... ad es. 00000001 + 00000100 = 00000101.
Armstrongest

@ Atomix: non lo faccio quasi più. Se ho bisogno di due flag, creo due campi booleani. Scrivevo codice in cui impacchettavo flag in questo modo e poi scrivevo "if flags & 0x110! = 0 then" o simili, ma questo è criptico e in questi giorni generalmente creo campi separati e scrivo "if fooFlag || barFlag " anziché. Non escluderei la possibilità di casi in cui imballare flag del genere è meglio per qualche motivo, ma non è più necessario salvare la memoria come una volta.
Jay

2
In realtà, è del tutto vale la pena di mettere in valigia bit, se si desidera che il calcolo per essere veloce - su quella grande quantità di dati memorizzati nella memoria. L'imballaggio di booleani non è solo per l'archiviazione più piccola, significa che puoi leggere i tuoi array di input booleani 8 volte più velocemente (in termini di larghezza di banda) rispetto a quando vengono decompressi, e questo è spesso abbastanza significativo. Inoltre, puoi utilizzare operazioni sui bit, come popc (conteggio della popolazione) che accelera il tuo lavoro sulla CPU stessa.
einpoklum

2
Un numero davvero enorme di booleani è ciò con cui lavori ogni giorno se lo fai: DBMS, apprendimento automatico, simulazioni scientifiche e tutta una serie di altre cose. E - solo lavorarci significa copiarli - dalla memoria alla cache. Un milione di bool non è niente, pensa miliardi.
einpoklum

1
@PeterCordes Sì, assolutamente, se avessi un insieme di valori booleani che erano logicamente la "stessa idea" in modo che io li consideri naturalmente come un "array" in un certo senso, e se poi li maschererò o li filtrerò o altrimenti eseguire operazioni bit per bit su di essi, quindi comprimerli in byte potrebbe avere senso. Come ho detto prima, mi viene difficile pensare all'ultima volta che ho lavorato a un'applicazione in cui si applicassero quelle condizioni, ma dai un paio di buoni esempi e sono sicuro che con un po 'di immaginazione si potrebbero pensare ad altri.
Jay

6

È possibile utilizzare i campi bit per ottenere numeri interi di dimensioni inferiori.

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

Anche se di solito viene utilizzato per mappare le strutture in base ai modelli di bit previsti dall'hardware:

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

Potresti avere bool a 1 bit e int a 4 e 2 bit. Ma ciò renderebbe un set di istruzioni strano per nessun miglioramento delle prestazioni perché è un modo innaturale di guardare l'architettura. In realtà ha senso "sprecare" una parte migliore di un byte piuttosto che cercare di recuperare i dati inutilizzati.

L'unica app che si preoccupa di impacchettare diversi bool in un singolo byte, nella mia esperienza, è Sql Server.


6

Perché un byte è la più piccola unità indirizzabile nella lingua.

Ma puoi fare in modo che bool prenda 1 bit, ad esempio, se ne hai molti, ad es. in una struttura, come questa:

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

2

boolpuò essere un byte - la dimensione indirizzabile più piccola della CPU, o può essere maggiore. Non è insolito avere boolle dimensioni di intper scopi di prestazione. Se per scopi specifici (ad esempio simulazione hardware) hai bisogno di un tipo con N bit, puoi trovare una libreria per quello (ad esempio la libreria GBL ha una BitSet<N>classe). Se sei preoccupato per la dimensione di bool(probabilmente hai un grande contenitore), puoi impacchettare i bit da solo, o usare std::vector<bool>quello lo farà per te (fai attenzione a quest'ultimo, poiché non soddisfa i requisiti del contenitore).


2

Pensa a come lo implementeresti a livello di emulatore ...

bool a[10] = {false};

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

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

2

Perché in generale, la CPU alloca la memoria con 1 byte come unità di base, sebbene alcune CPU come MIPS utilizzino una parola di 4 byte.

Tuttavia si vectoroccupa boolin modo speciale, con vector<bool>un bit per ogni bool viene assegnato.


1
Credo che anche la CPU MIPS ti darà accesso a un singolo byte, anche se c'è una penalizzazione delle prestazioni.
Paul Tomblin

@Paul: Sì, hai ragione, ma generalmente le parole specifiche lw/ swsono molto più usate.
Ryan Li

Non conosco MIPS, ma l'architettura IA-64 consente l'accesso solo su un confine a 64 bit.
Gene Bushuyev

0

Il byte è l'unità più piccola di archiviazione dei dati digitali di un computer. In un computer la RAM ha milioni di byte e ognuno di loro ha un indirizzo. Se avesse un indirizzo per ogni bit, un computer potrebbe gestire 8 volte meno RAM di quanto può.

Maggiori informazioni: Wikipedia


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.