Wie bekomme ich ein Array von Bits in einer Struktur?

Lesezeit: 9 Minuten

Benutzer-Avatar
Shahbaz

Ich habe nachgedacht (und suche daher nach einer Möglichkeit, dies zu lernen, und keine bessere Lösung), wenn es möglich ist, ein Array von Bits in einer Struktur zu erhalten.

Lassen Sie es mich an einem Beispiel demonstrieren. Stellen Sie sich einen solchen Code vor:

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

In diesem Code haben wir 4 einzelne Bits in einer Struktur verpackt. Auf sie kann einzeln zugegriffen werden, wodurch die Aufgabe der Bitmanipulation dem Compiler überlassen wird. Was ich mich gefragt habe, ist, ob so etwas möglich ist:

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

Ich habe versucht zu deklarieren bits in struct B wie unsigned int bits[4]:1 oder unsigned int bits:1[4] oder ähnliches ohne erfolg. Meine beste Vermutung war typedef unsigned int bit:1; und verwenden bit wie der Typ, funktioniert aber immer noch nicht.

Meine Frage ist, ist so etwas möglich? Wenn ja, wie? Wenn nein, warum nicht? Das 1-Bit unsigned int ist ein gültiger Typ, also warum sollten Sie nicht in der Lage sein, ein Array davon zu erhalten?

Auch hier möchte ich keinen Ersatz dafür, ich frage mich nur, wie so etwas möglich ist.

PS Ich markiere dies als C++, obwohl der Code in C geschrieben ist, weil ich annehme, dass die Methode in beiden Sprachen vorhanden wäre. Wenn es einen C++-spezifischen Weg gibt (durch Verwendung der Sprachkonstrukte, nicht der Bibliotheken), wäre ich auch daran interessiert zu wissen.

UPDATE: Mir ist völlig bewusst, dass ich die Bitoperationen selbst durchführen kann. Ich habe es in der Vergangenheit tausendmal getan. Ich bin NICHT an einer Antwort interessiert, die besagt, dass Sie stattdessen ein Array / einen Vektor verwenden und Bitmanipulationen durchführen. Ich denke nur, ob DIESES KONSTRUKT möglich ist oder nicht, KEINE Alternative.

Update: Antwort für die Ungeduldigen (danke an neagoegab):

Anstatt von

typedef unsigned int bit:1;

ich könnte benutzen

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

richtig verwenden #pragma pack

  • Die Verwendung von Bitfeldern macht es schwierig, Ihr Programm zu portieren … sind Sie sicher, dass Sie sie brauchen?

    – Karl Norum

    15. November 2011 um 21:17 Uhr

  • @CarlNorum Habe ich nicht schon 10 Mal erwähnt, dass ich nur neugierig bin?

    – Shahbaz

    15. November 2011 um 21:17 Uhr

  • In diesem Fall gibt es meines Wissens keine Möglichkeit, ein Array von Bitfeldern zu erstellen.

    – Karl Norum

    15. November 2011 um 21:18 Uhr

  • Das Layout der Bitfelder ist implementierungsabhängig. Also nein, anstatt einfacher zu sein, entpuppt es sich oft als Albtraum der Portabilität. Die bitweisen Operatoren haben alle eine wohldefinierte Semantik.

    – Karl Norum

    15. November 2011 um 21:20 Uhr


  • @CarlNorum: Es ist nur ein Portabilitäts-Albtraum, wenn Sie versuchen, Ihre Struktur in/aus einem Array von Bytes umzuwandeln und ein bestimmtes Layout erwarten. Wenn Sie nur Bits effizient in einer Struktur speichern möchten, gibt es kein Portabilitätsproblem.

    – Craig McQueen

    16. November 2011 um 4:50 Uhr

Benutzer-Avatar
Freude

NICHT MÖGLICHSo ein Konstrukt Ist nicht möglich(hier)NICHT MÖGLICH

Man könnte versuchen, dies zu tun, aber das Ergebnis wird das sein Ein Bit wird in einem Byte gespeichert

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

Ausgang:

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**

Um auf einzelne Bits aus einem Byte zuzugreifen, hier ein Beispiel (Bitte beachten Sie, dass das Layout der Bitfelder implementierungsabhängig ist)

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

  • Was Ihre zweite Methode betrifft, bekommt diese Vereinigung nicht alles hin _bit* Bits auf demselben überlappenden Bit? Meinten Sie nicht struct Bit{ union{ char _value; struct { char _bit0:1; char _bit1:1; ....} _bits; }; };?

    – Shahbaz

    15. November 2011 um 23:17 Uhr

  • Könnten Sie diese bitte erläutern pragma packs? Sind sie Standard C oder Visual C spezifisch?

    – Shahbaz

    15. November 2011 um 23:21 Uhr

  • pragma pack ist implementierungsdefiniert, weil dies nicht der Fall ist pragma STDC (ISO 9899:1999(S)6.10.6.1). Soweit ich weiß, ist es für MSVC und GCC definiert.

    – Moschbär

    16. November 2011 um 0:02 Uhr

  • Ansehen en.wikipedia.org/wiki/Data_structure_alignment für eine genauere Erklärung dessen, was genau pragma pack tut.

    – Moschbär

    16. November 2011 um 0:04 Uhr


  • @Shahbaz, ja, es sollte so sein, wie du es gesagt hast, entschuldige dich für das späte Update und danke.

    – Freude

    24. Dezember 2013 um 8:55 Uhr

Benutzer-Avatar
Markus B

In C++ verwenden Sie std::bitset<4>. Dadurch wird eine minimale Anzahl von Wörtern zum Speichern verwendet und die gesamte Maskierung vor Ihnen verborgen. Es ist wirklich schwierig, die C++-Bibliothek von der Sprache zu trennen, da so viel von der Sprache in der Standardbibliothek implementiert ist. In C gibt es keine direkte Möglichkeit, ein solches Array aus einzelnen Bits zu erstellen, stattdessen würden Sie ein Element aus vier Bits erstellen oder die Manipulation manuell vornehmen.

BEARBEITEN:

Das 1-Bit unsigned int ist ein gültiger Typ, also warum sollten Sie nicht in der Lage sein, ein Array davon zu erhalten?

Eigentlich können Sie einen 1-Bit-Typ ohne Vorzeichen nirgendwo anders als im Kontext der Erstellung eines Struktur-/Klassenmitglieds verwenden. An diesem Punkt unterscheidet es sich so sehr von anderen Typen, dass es nicht automatisch folgt, dass Sie ein Array davon erstellen könnten.

  • Ich habe zwar ausdrücklich erwähnt, dass ich mich nicht für Bibliotheken interessiere (da es sowieso einfach wäre, selbst eine zu implementieren), aber trotzdem +1, weil ich gelernt habe std::bitset existiert.

    – Shahbaz

    15. November 2011 um 21:31 Uhr


Benutzer-Avatar
moschbär

C++ verwenden würde std::vector<bool> oder std::bitset<N>.

In C zu emulieren std::vector<bool> Semantik verwenden Sie eine Struktur wie diese:

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

wo Word ist ein implementierungsdefinierter Typ, der in der Breite gleich dem Datenbus der CPU ist; wordsizewie später verwendet, ist gleich der Breite des Datenbusses.

Z.B Word ist uint32_fast_t für 32-Bit-Rechner, uint64_fast_t für 64-Bit-Maschinen;
wordsize ist 32 für 32-Bit-Rechner und 64 für 64-Bit-Rechner.

Sie verwenden Funktionen/Makros zum Setzen/Löschen von Bits.

Um ein bisschen zu extrahieren, verwenden Sie GET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] & (1 << ((bit) % wordsize))).

Um ein bisschen einzustellen, verwenden Sie SET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] |= (1 << ((bit) % wordsize))).

Um ein bisschen zu löschen, verwenden Sie CLEAR_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize))).

Um ein bisschen zu kippen, verwenden Sie FLIP_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] ^= (1 << ((bit) % wordsize))).

So fügen Sie die Größenänderung gemäß hinzu std::vector<bool>machen Sie eine Größenänderungsfunktion, die aufruft realloc an Bits.word und Änderungen Bits.word_count entsprechend. Die genauen Details davon bleiben als Problem übrig.

Dasselbe gilt für eine ordnungsgemäße Bereichsprüfung von Bit-Indizes.

  • Danke, dass Sie sich die Mühe gemacht haben, Bitoperationen zu erklären, aber das war mir klar. Meine Frage bezog sich auf diese spezifische Verwendung (wobei die Bits eher vom Compiler als von mir manipuliert wurden). Auch hier benutze ich so etwas nicht wirklich, sondern denke nur darüber nach.

    – Shahbaz

    15. November 2011 um 21:29 Uhr

  • Zitieren des JSF Coding Style Guide: Bitset-Strukturen sollten vermieden werden, es sei denn, sie sind mit Hardware verbunden. Dafür gibt es einen guten Grund – sie machen mehr Ärger, als sie wert sind. Ich bin mir ziemlich sicher, dass das auch in MISRA enthalten ist, aber ich habe keine 15 Dollar übrig, um das Papier zu kaufen, daher kann ich keine endgültige Antwort geben.

    – Moschbär

    15. November 2011 um 21:31 Uhr


  • @Shahbaz: Nein, das kann der Compiler nicht.

    – Muhende Ente

    15. November 2011 um 22:11 Uhr

  • Selbst bei Schnittstellen mit Hardware sind native Bitfelder von geringem Nutzen, sicherlich nicht in einer Weise, die portierbar ist und es nicht erforderlich macht, dass der Benutzer sorgfältig überprüft, wie seine Implementierung funktioniert, bevor er Code schreibt. Ich habe meine eigenen Bitfeld-/Endianness-Bibliotheken erstellt – einschließlich einer, die “Arrays von Bitfeldern” zulässt -, um dies zu beheben, und habe es nie bereut.

    – Unterstrich_d

    20. Januar 2016 um 13:52 Uhr

das ist missbräuchlich und beruht auf einer Erweiterung … aber es hat bei mir funktioniert:

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

Sie können auch ein Array von ganzen Zahlen (ints oder longs) verwenden, um eine beliebig große Bitmaske zu erstellen. Der Systemaufruf select() verwendet diesen Ansatz für seinen Typ fd_set; jedes Bit entspricht dem nummerierten Dateideskriptor (0..N). Makros sind definiert: FD_CLR zum Löschen eines Bits, FD_SET zum Setzen eines Bits, FD_ISSET zum Testen eines Bits und FD_SETSIZE ist die Gesamtzahl der Bits. Die Makros finden automatisch heraus, auf welche Ganzzahl im Array zugegriffen werden soll und auf welches Bit in der Ganzzahl. Unter Unix siehe “sys/select.h”; unter Windows ist es glaube ich in “winsock.h”. Sie können die FD-Technik verwenden, um Ihre eigenen Definitionen für eine Bitmaske zu machen. Ich nehme an, Sie könnten in C++ ein Bitmaskenobjekt erstellen und das überladen [] Operator, um auf einzelne Bits zuzugreifen.

Sie können eine Bitliste erstellen, indem Sie einen Strukturzeiger verwenden. Dies verbraucht jedoch mehr als ein Bit Platz pro geschriebenem Bit, da es ein Byte (für eine Adresse) pro Bit verwendet:

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

Dann danach:

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

Sie können wie folgt darauf zugreifen:

bitstream[bitpointer].bit=...

1370330cookie-checkWie bekomme ich ein Array von Bits in einer Struktur?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy