web-dev-qa-db-fra.com

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 <stdio.h>

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 <stdio.h>

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 bits dans struct B en tant que unsigned int bits[4]:1 ou unsigned int bits:1[4] ou des choses similaires en vain. Ma meilleure hypothèse était de typedef unsigned int bit:1; et d'utiliser bit comme type, mais cela ne fonctionne toujours pas.

Ma question est, est-ce qu'une telle chose est possible? Si oui comment? Si non pourquoi pas Le 1 uns 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.

P.S. J'écris ceci 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 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;

utilisant correctement #pragma pack

27
Shahbaz

NON POSSIBLE - Une construction comme celle-ci IS NON possible ( ici ) - NON POSSIBLE

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

#include <cstdint>
#include <iostream>
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] <<endl;

    cout<< sizeof(Bit) << endl;
    cout<< sizeof(B) << endl;

    return 0;
}

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 (notez que la disposition des champs de bits dépend de la mise en œuvre)

#include <iostream>
#include <cstdint>
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 <<endl;
    cout << "Bit 1: " << (int)myByte._bit1 <<endl;
    cout << "Bit 2: " << (int)myByte._bit2 <<endl;
    cout << "Bit 3: " << (int)myByte._bit3 <<endl;
    cout << "Bit 4: " << (int)myByte._bit4 <<endl;
    cout << "Bit 5: " << (int)myByte._bit5 <<endl;
    cout << "Bit 6: " << (int)myByte._bit6 <<endl;
    cout << "Bit 7: " << (int)myByte._bit7 <<endl;

    if(myByte._bit3)
    {
        cout << "Bit 3 is on" << endl;
    }
}
9
neagoegab

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.

6
Mark B

C++ utiliserait std::vector<bool> ou std::bitset<N>.

En C, pour émuler la sémantique std::vector<bool>, 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 ayant une largeur égale à celle du bus de données de la CPU; wordsize, tel qu'utilisé plus tard, est égal à la largeur du bus de données.

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

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

Pour extraire un peu, 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 peu, utilisez CLEAR_BIT(bits, bit) (((bits)->)Word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize))).

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

Pour ajouter la possibilité de redimensionnement selon std::vector<bool>, créez une fonction de redimensionnement qui appelle realloc sur Bits.Word et modifie Bits.Word_count en conséquence. Les détails exacts de cela restent un problème.

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

4
moshbear

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

struct __attribute__ ((__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;
}
2
Grady Player

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 objet masque de bits et surcharger l'opérateur [] pour accéder à des bits individuels.

0
Alex Measday