Pourquoi un booléen a-t-il 1 octet et non 1 bit de taille?


127

En C ++,

  • Pourquoi un booléen a-t-il 1 octet et non 1 bit de taille?
  • Pourquoi n'y a-t-il pas de types comme des entiers 4 bits ou 2 bits?

Je manque les choses ci-dessus lors de l'écriture d'un émulateur pour un processeur


10
En C ++, vous pouvez "compresser" les données en utilisant des champs de bits. struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };. La plupart des compilateurs allouent un fichier complet unsigned int, mais ils gèrent eux-mêmes le bit-twiddling lorsque vous lisez / écrivez. Ils s'occupent également seuls des opérations modulo. C'est un unsigned small : 4attribut qui a une valeur entre 0 et 15, et quand il devrait arriver à 16, il n'écrasera pas le bit précédent :)
Matthieu M.

Réponses:


208

Parce que le CPU ne peut pas adresser quoi que ce soit de plus petit qu'un octet.


10
Merde, maintenant c'est maladroit Sir
Asm

31
En fait, les quatre x86 instructions bt, bts, btret btc peuvent répondre à des bits uniques!
fredoverflow

11
Je pense qu'il btadresse un décalage d'octet, puis teste le bit à un décalage donné, peu importe, lorsque vous spécifiez une adresse, vous entrez en octets ... les littéraux de décalage de bits deviendraient un peu verbeux (excusez le jeu de mots).
user7116

2
@six: Vous pouvez charger le début d'un tableau dans un registre, puis le "décalage de bits" relatif dans une seconde. Le décalage de bits n'est pas limité à "dans un octet", il peut s'agir de n'importe quel nombre de 32 bits.
fredoverflow

4
Eh bien, oui et non. Nous avons des champs de bits, et nous pourrions avoir un pointeur de champ de bits, c'est-à-dire adresse + numéro de bit. De toute évidence, un tel pointeur ne serait pas convertible en void * en raison de l'exigence de stockage supplémentaire pour le nombre de bits.
Maxim Egorushkin

32

De Wikipedia :

Historiquement, un octet était le nombre de bits utilisés pour coder un seul caractère de texte dans un ordinateur et c'est pour cette raison l'élément adressable de base dans de nombreuses architectures informatiques.

L'octet est donc l' unité adressable de base , en dessous de laquelle l'architecture informatique ne peut pas adresser. Et comme il n'existe pas (probablement) d'ordinateurs prenant en charge l'octet de 4 bits, vous n'avez pas de 4 bits, bool etc.

Cependant, si vous pouvez concevoir une telle architecture qui peut adresser 4 bits comme unité adressable de base, alors vous aurez alors une booltaille de 4 bits, sur cet ordinateur uniquement!


4
"vous aurez alors un int de taille 4 bits, sur cet ordinateur uniquement" - non, vous ne le ferez pas, car la norme interdit à CHAR_BIT d'être inférieur à 8. Si l'unité adressable sur l'architecture est inférieure à 8 bits, alors un L'implémentation C ++ devra simplement présenter un modèle de mémoire différent du modèle de mémoire du matériel sous-jacent.
Steve Jessop

@Steve: oups ... J'ai oublié ça. Supprimé intet charde mon message.
Nawaz

1
vous ne pouvez pas non plus avoir de 4 bits bool, car charc'est la plus petite unité adressable en C ++ , indépendamment de ce que l'architecture peut adresser avec ses propres opcodes. sizeof(bool)doit avoir une valeur d'au moins 1, et les boolobjets adjacents doivent avoir leurs propres adresses en C ++ , donc l'implémentation doit simplement les agrandir et gaspiller de la mémoire. C'est pourquoi les champs de bits existent en tant que cas particulier: les membres de champ de bits d'une structure ne sont pas tenus d'être adressables séparément, ils peuvent donc être plus petits que a char(bien que la structure entière ne puisse toujours pas l'être).
Steve Jessop

@ Steve Jessop: cela semble intéressant. pourriez-vous s'il vous plaît me donner la référence de la spécification du langage où il charest indiqué que c'est la plus petite unité adressable en C ++?
Nawaz

3
la déclaration spécifique la plus proche est probablement 3.9 / 4: "La représentation objet d'un objet de type T est la séquence de N objets char non signés repris par l'objet de type T, où N est égal à sizeof (T)". Évidemment, sizeof(bool)ne peut pas être 0,5 :-) Je suppose qu'une implémentation pourrait légalement fournir des pointeurs sous-octets comme extension, mais les objets "ordinaires" comme bool, alloués de manière ordinaire, doivent faire ce que dit la norme.
Steve Jessop

12

La réponse la plus simple est; c'est parce que le CPU adresse la mémoire en octets et non en bits, et les opérations au niveau du bit sont très lentes.

Cependant, il est possible d'utiliser l'allocation de taille en bits en C ++. Il existe une spécialisation std :: vector pour les vecteurs binaires, ainsi que des structures prenant des entrées de taille binaire.


1
Pas sûr que je serais d'accord pour dire que les opérations au niveau du bit sont lentes. ands, nots, xors etc sont très rapides. C'est généralement l'implémentation des opérations au niveau du bit qui sont lentes. Au niveau de la machine, ils sont assez rapides. Ramification ... maintenant c'est lent.
Hogan

3
Juste pour être plus clair, si vous créez un vecteur de booléens et y mettez 24 booléens, cela ne prendra que 3 octets (3 * 8). Si vous mettez un autre booléen, il prendra un autre octet. Pourtant, si vous poussez un autre booléen, il ne prendra pas d'octets supplémentaires car il utilise les bits "libres" dans le dernier octet
Pedro Loureiro

oui, je doute aussi que les opérations par morsure soient lentes :)
Pedro Loureiro

Les vecteurs binaires ne créent pas d'allocations de taille binaire. ils créent des allocations de la taille d'un octet. Il n'est pas possible d'allouer un seul bit.
John Dibling

1
La lecture d'un seul bit dans un vecteur de bits nécessite trois opérations: décalage, et, et un autre décalage à nouveau. L'écriture est deux. Alors que les octets individuels peuvent être accédés avec un seul.
sukru

7

À l'époque où je devais aller à l'école à pied dans une tempête de neige déchaînée, en montée dans les deux sens, et que le déjeuner était n'importe quel animal que nous pouvions traquer dans les bois derrière l'école et tuer à mains nues, les ordinateurs avaient beaucoup moins de mémoire disponible que aujourd'hui. Le premier ordinateur que j'ai jamais utilisé avait 6K de RAM. Pas 6 mégaoctets, pas 6 gigaoctets, 6 kilo-octets. Dans cet environnement, il était très logique de regrouper autant de booléens que possible dans un int, et nous utiliserions donc régulièrement des opérations pour les supprimer et les insérer.

Aujourd'hui, quand les gens se moqueront de vous pour n'avoir que 1 Go de RAM, et que le seul endroit où vous pourriez trouver un disque dur avec moins de 200 Go est dans un magasin d'antiquités, cela ne vaut tout simplement pas la peine d'emballer des bits.


Sauf lorsqu'il s'agit de drapeaux. Des choses comme définir plusieurs options sur quelque chose ... par exemple. 00000001 + 00000100 = 00000101.
Armstrongest

@Atomix: Je ne fais presque plus jamais ça. Si j'ai besoin de deux indicateurs, je crée deux champs booléens. J'avais l'habitude d'écrire du code où j'emballais des drapeaux comme ça, puis j'écrivais "if flags & 0x110! = 0 then" ou autre, mais c'est cryptique et ces jours-ci, je fais généralement des champs séparés et j'écris "if fooFlag || barFlag " au lieu. Je n'exclurais pas la possibilité de cas où emballer des drapeaux comme celui-ci est préférable pour une raison quelconque, mais il n'est plus nécessaire d'économiser de la mémoire comme avant.
Jay

2
En fait, il est tout à fait utile de votre peine d'emballer les bits, si vous voulez que votre calcul pour être rapide - sur cette grande quantité de données que vous stockez dans la mémoire. Emballer des booléens n'est pas seulement pour un stockage plus petit - cela signifie que vous pouvez lire vos tableaux d'entrée booléens 8 fois plus rapidement (en termes de bande passante) que lorsqu'ils sont déballés, et c'est souvent assez important. En outre, vous pouvez utiliser des opérations sur bits, comme popc (population), qui accélère votre travail sur le processeur lui-même.
einpoklum

2
Un très grand nombre de booléens est ce avec quoi vous travaillez chaque jour si vous le faites: des SGBD, l'apprentissage automatique, des simulations scientifiques et une foule d'autres choses. Et - simplement travailler dessus signifie les copier - de la mémoire vers le cache. Un million de bools n'est rien, pensez à des milliards.
einpoklum

1
@PeterCordes Oui, absolument, si j'avais un ensemble de booléens qui étaient logiquement la "même idée" de sorte que je les considère naturellement comme un "tableau" dans un certain sens, et si je vais ensuite les masquer ou les filtrer ou sinon, effectuez des opérations au niveau du bit sur eux, puis les regrouper en octets pourrait avoir du sens. Comme je l'ai dit plus tôt, j'ai du mal à penser à la dernière fois que j'ai travaillé sur une application où ces conditions s'appliquaient, mais vous donnez quelques bons exemples, et je suis sûr qu'avec un peu d'imagination, on pourrait penser à d'autres.
Jay

6

Vous pouvez utiliser des champs de bits pour obtenir des entiers de taille inférieure.

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

Bien qu'il soit généralement utilisé pour mapper les structures aux modèles de bits attendus par le matériel:

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

Vous pourriez avoir des booléens 1 bit et des entiers 4 et 2 bits. Mais cela ferait un ensemble d'instructions étrange sans gain de performance, car c'est une façon non naturelle de regarder l'architecture. Il est en fait logique de «gaspiller» une meilleure partie d'un octet plutôt que d'essayer de récupérer ces données inutilisées.

La seule application qui dérange pour emballer plusieurs booléens dans un seul octet, d'après mon expérience, est Sql Server.


6

Parce qu'un octet est la plus petite unité adressable de la langue.

Mais vous pouvez faire en sorte que bool prenne 1 bit par exemple si vous en avez un tas, par exemple. dans une structure, comme ceci:

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

2

boolpeut être un octet - la plus petite taille adressable du processeur, ou peut être plus grande. Il n'est pas inhabituel d'avoir boolla taille de intpour des raisons de performance. Si à des fins spécifiques (par exemple la simulation matérielle) vous avez besoin d'un type avec N bits, vous pouvez trouver une bibliothèque pour cela (par exemple, la bibliothèque GBL a une BitSet<N>classe). Si vous êtes préoccupé par la taille de bool(vous avez probablement un gros conteneur,), vous pouvez emballer des bits vous-même, ou utiliser std::vector<bool>qui le fera pour vous (soyez prudent avec ce dernier, car il ne répond pas aux exigences du conteneur).


2

Pensez à la façon dont vous implémenteriez cela au niveau de votre émulateur ...

bool a[10] = {false};

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

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

2

Parce qu'en général, le CPU alloue de la mémoire avec 1 octet comme unité de base, bien que certains CPU comme MIPS utilisent un mot de 4 octets.

Cependant vectortraite boold'une manière spéciale, avec vector<bool>un bit pour chaque booléen est attribué.


1
Je crois que même le processeur MIPS vous donnera accès à un octet individuel, bien qu'il y ait une pénalité de performance.
Paul Tomblin

@Paul: Oui, vous avez raison, mais généralement les mots spécifiques lw/ swsont beaucoup plus utilisés.
Ryan Li

Je ne sais pas sur MIPS, mais l'architecture IA-64 ne permet l'accès que sur une limite de 64 bits.
Gene Bushuyev

0

L'octet est la plus petite unité de stockage de données numériques d'un ordinateur. Dans un ordinateur, la RAM a des millions d'octets et n'importe lequel d'entre eux a une adresse. S'il avait une adresse pour chaque bit, un ordinateur pourrait gérer 8 fois moins de RAM que ce qu'il peut.

Plus d'informations: Wikipedia


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.