Comment obtenir un tableau de bits dans une structure?

Je réfléchissais (et cherche donc un moyen d’apprendre cela, et non une meilleure solution ) s’il est possible d’obtenir un tableau de bits dans une structure.

Permettez-moi de démontrer par un exemple. Imaginez un tel code:

#include  struct A { unsigned int bit0:1; unsigned int bit1:1; unsigned int bit2:1; unsigned int bit3:1; }; int main() { struct A a = {1, 0, 1, 1}; printf("%u\n", a.bit0); printf("%u\n", a.bit1); printf("%u\n", a.bit2); printf("%u\n", a.bit3); return 0; } 

Dans ce code, nous avons 4 bits individuels emballés dans une structure. Ils peuvent être consultés individuellement, laissant le travail de manipulation de bits au compilateur. Ce que je me demandais, c’est si une telle chose est possible:

 #include  typedef unsigned int bit:1; struct B { bit bits[4]; }; int main() { struct B b = {{1, 0, 1, 1}}; for (i = 0; i < 4; ++i) printf("%u\n", b.bits[i]); return 0; } 

J’ai essayé de déclarer les bits de la struct B comme étant unsigned int bits[4]:1 ou unsigned int bits:1[4] ou des objects similaires, en vain. Ma meilleure hypothèse était de typedef unsigned int bit:1; et utilisez bit comme type, mais ne fonctionne toujours pas.

Ma question est, est-ce qu’une telle chose est possible? Si oui comment? Si non pourquoi pas Le 1 bit unsigned int est un type valide, alors pourquoi ne devriez-vous pas pouvoir en obtenir un tableau?

Encore une fois, je ne veux pas de remplacement pour cela, je me demande simplement comment une telle chose est possible.

PS Je l’étiquette en C ++, bien que le code soit écrit en C, car je suppose que la méthode serait existante dans les deux langages. S’il existe un moyen spécifique de le faire pour C ++ (en utilisant les constructions de langage, pas les bibliothèques), je serais également intéressé de le savoir.

UPDATE: Je suis tout à fait conscient que je peux faire les opérations de bits moi-même. Je l’ai fait mille fois dans le passé. Je ne suis PAS intéressé par une réponse qui dit d’utiliser un tableau / vecteur à la place et de faire une manipulation de bits. Je pense seulement que si CETTE CONSTRUCTION est possible ou non, PAS une alternative.

Mise à jour: réponse pour les impatients (merci à neagoegab):

Au lieu de

 typedef unsigned int bit:1; 

je pourrais utiliser

 typedef struct { unsigned int value:1; } bit; 

en utilisant correctement #pragma pack

PAS POSSIBLE – Une construction comme ça N’EST PAS possible ( ici ) – NON POSSIBLE

On pourrait essayer de faire cela, mais le résultat sera qu’un bit est stocké dans un octet

 #include  #include  using namespace std; #pragma pack(push, 1) struct Bit { //one bit is stored in one BYTE uint8_t a_:1; }; #pragma pack(pop, 1) typedef Bit bit; struct B { bit bits[4]; }; int main() { struct B b = {{0, 0, 1, 1}}; for (int i = 0; i < 4; ++i) cout << b.bits[i] < 

sortie:

 0 //bit[0] value 0 //bit[1] value 1 //bit[2] value 1 //bit[3] value 1 //sizeof(Bit), **one bit is stored in one byte!!!** 4 //sizeof(B), ** 4 bytes, each bit is stored in one BYTE** 

Pour accéder aux bits individuels d'un octet, voici un exemple (veuillez noter que la disposition des champs de bits dépend de la mise en œuvre)

 #include  #include  using namespace std; #pragma pack(push, 1) struct Byte { Byte(uint8_t value): _value(value) { } union { uint8_t _value; struct { uint8_t _bit0:1; uint8_t _bit1:1; uint8_t _bit2:1; uint8_t _bit3:1; uint8_t _bit4:1; uint8_t _bit5:1; uint8_t _bit6:1; uint8_t _bit7:1; }; }; }; #pragma pack(pop, 1) int main() { Byte myByte(8); cout << "Bit 0: " << (int)myByte._bit0 < 

En C ++, vous utilisez std::bitset<4> . Cela utilisera un nombre minimal de mots pour le stockage et cachera tout le masquage de votre part. Il est très difficile de séparer la bibliothèque C ++ du langage car une grande partie du langage est implémentée dans la bibliothèque standard. En C, il n’existe aucun moyen direct de créer un tableau de bits simples comme celui-ci. Vous pouvez plutôt créer un élément de quatre bits ou effectuer la manipulation manuellement.

MODIFIER:

Le 1 bit unsigned int est un type valide, alors pourquoi ne devriez-vous pas pouvoir en obtenir un tableau?

En réalité, vous ne pouvez pas utiliser un type non signé 1 bit ailleurs que dans le contexte de la création d’un membre struct / class. À ce stade, il est si différent des autres types qu’il ne s’ensuit pas automatiquement que vous pouvez en créer un tableau.

C ++ utiliserait std::vector ou std::bitset .

En C, pour émuler la sémantique std::vector , vous utilisez une structure comme celle-ci:

 struct Bits { Word word[]; size_t word_count; }; 

Word est un type défini par l’implémentation dont la largeur est égale à celle du bus de données de la CPU; wordsize , comme nous le wordsize plus tard, est égal à la largeur du bus de données.

Par exemple, Word est uint32_fast_t pour les machines 32 bits, uint64_fast_t pour les machines 64 bits; wordsize est 32 pour les machines 32 bits et 64 pour les machines 64 bits.

Vous utilisez des fonctions / macros pour définir / effacer des bits.

Pour extraire un bit, utilisez GET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] & (1 << ((bit) % wordsize))) .

Pour définir un bit, utilisez SET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] |= (1 << ((bit) % wordsize))) .

Pour effacer un bit, utilisez CLEAR_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize))) .

Pour FLIP_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] ^= (1 << ((bit) % wordsize))) un bit, utilisez FLIP_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] ^= (1 << ((bit) % wordsize))) .

Pour append la redimensionnement selon std::vector , créez une fonction de redimensionnement qui appelle realloc sur Bits.word et modifie Bits.word_count conséquence. Les détails exacts de cela restnt un problème.

Il en va de même pour la vérification correcte de la plage des indices de bits.

c’est abusif, et repose sur une extension … mais ça a fonctionné pour moi:

 struct __atsortingbute__ ((__packed__)) A { unsigned int bit0:1; unsigned int bit1:1; unsigned int bit2:1; unsigned int bit3:1; }; union U { struct A structVal; int intVal; }; int main() { struct A a = {1, 0, 1, 1}; union U u; u.structVal = a; for (int i =0 ; i<4; i++) { int mask = 1 << i; printf("%d\n", (u.intVal & mask) >> i); } return 0; } 

Vous pouvez également utiliser un tableau d’entiers (ints ou longs) pour construire un masque de bits arbitrairement volumineux. L’appel système select () utilise cette approche pour son type fd_set; chaque bit correspond au descripteur de fichier numéroté (0..N). Les macros sont définies: FD_CLR pour effacer un bit, FD_SET pour définir un bit, FD_ISSET pour tester un bit et FD_SETSIZE est le nombre total de bits. Les macros déterminent automatiquement à quel entier du tableau accéder et quel bit du nombre. Sous Unix, voir “sys / select.h”; sous Windows, je pense que c’est dans “winsock.h”. Vous pouvez utiliser la technique FD pour créer vos propres définitions pour un masque de bits. En C ++, je suppose que vous pouvez créer un object masque de bits et surcharger l’opérateur [] pour accéder à des bits individuels.

Vous pouvez créer une liste de bits en utilisant un pointeur struct. Ceci utilisera cependant plus que peu d’espace par bit écrit, puisqu’il utilisera un octet (pour une adresse) par bit:

 struct bitfield{ unsigned int bit : 1; }; struct bitfield *bitstream; 

Puis après ceci:

 bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant ); 

Vous pouvez y accéder comme suit:

 bitstream[bitpointer].bit=...