Ist es möglich, ein Array von Bitfeldern zu verwenden?

Lesezeit: 4 Minuten

Benutzer-Avatar
msc

Ich bin neugierig zu wissen, Ist es möglich, ein Array von Bitfeldern zu verwenden? Wie:

struct st
{
  unsigned int i[5]: 4;
}; 

  • Beachten Sie das am meisten jüngste C-Code verwendet keine Bitfelder mehr. Eine nützliche Alternative wäre die Verwendung von Bitmaskenfeldern und die Durchführung bitweiser Operationen an ihnen. Übrigens generiert der Compiler äquivalenten Code.

    – Basile Starynkevitch

    29. Januar 2017 um 7:39 Uhr


  • @BasileStarynkevitch: Ich frage mich, woher Sie das ableiten. Die Verwendung von Bitfeldern ist viel weniger fehleranfällig als die Behandlung von Bitmaskenfeldern mit bitweisen Operationen.

    – chqrlie

    4. Februar 2017 um 22:22 Uhr

Benutzer-Avatar
hackt

Nein, das kannst du nicht. Das Bitfeld kann nur mit Variablen vom Typ Integral verwendet werden.

C11-§6.7.2.1/5

Ein Bitfeld muss einen Typ haben, der eine qualifizierte oder nicht qualifizierte Version davon ist _Bool, signed int, unsigned intoder einen anderen implementierungsdefinierten Typ.

Alternativ können Sie dies tun

struct st
{
    unsigned int i: 4;  
} arr_st[5]; 

aber seine Größe wird fünfmal so groß sein wie a struct (wie im Kommentar von @Jonathan Leffler erwähnt) mit jeweils 5 Mitgliedern mit Bitfeld 4. Hier macht es also wenig Sinn.

Genauer können Sie dies tun

struct st
{
    uint8_t i: 4;   // Will take only a byte
} arr_st[5]; 

  • Aber die Größe davon (struct st { unsigned int i: 4; } arr_st[5]; wäre höchstwahrscheinlich 5 mal so groß wie ein unsigned int; es wäre nicht 20 Bit lang.

    – Jonathan Leffler

    29. Januar 2017 um 7:10 Uhr

  • @JonathanLeffler; Ja. Aber keine anderen Möglichkeiten, ein Array von Bitfeldern zu deklarieren.

    – Hacken

    29. Januar 2017 um 7:22 Uhr


  • @hackks Danke, dass du mir geholfen hast.

    – msc

    29. Januar 2017 um 7:55 Uhr

  • Typ uint8_t möglicherweise nicht verfügbar. struct st { unsigned char i: 4; } arr_st[5]; oder nur unsigned char arr[5]; scheinen vorzuziehen.

    – chqrlie

    29. Januar 2017 um 8:13 Uhr


  • @IlmariKaronen; Ich meine struct arr_st wird sein 5 mal struct like struct stt { unsigned int i: 4; unsigned int j: 4; unsigned int k: 4; unsigned int l: 4; unsigned int m: 4; } s;

    – Hacken

    29. Januar 2017 um 13:53 Uhr

Benutzer-Avatar
chqrlie

C unterstützt keine Arrays von Bitfeldern, daher lautet die kurze Antwort nein.

Bei sehr großen Arrays kann es sich lohnen, Werte zu packen, 2 pro Byte, auf diese Weise:

#define ARRAY_SIZE  1000000

unsigned char arr[(ARRAY_SIZE + 1) / 2];

int get_4bits(const unsigned char *arr, size_t index) {
    return arr[index >> 1] >> ((index & 1) << 2);
}

int set_4bits(unsigned char *arr, size_t index, int value) {
    arr[index >> 1] &= ~ 0x0F << ((index & 1) << 2);
    arr[index >> 1] |= (value & 0x0F) << ((index & 1) << 2);
}

Benutzer-Avatar
Tomasz Gawel

Sie können für diesen Fall Ihre eigene Klasse schreiben. Zum Beispiel:

template <typename T, size_t ITEM_BIT_SIZE>
class BitArrayView {
private:
    static const size_t ARRAY_ENTRY_BITS = sizeof(T) * 8;
    static const T ITEM_MASK = (~((T) 0)) >> (ARRAY_ENTRY_BITS - ITEM_BIT_SIZE);
    T* arr;
public:
    struct ItemMutator {
        BitArrayView* owner;
        size_t index;
        T operator=(T value) {
            return owner->set(index, value);
        }
        operator T() {
            return owner->get(index);
        }
    };
    const size_t bitSize;
    BitArrayView(T* arr, size_t length) : arr(arr), bitSize((length * ARRAY_ENTRY_BITS) / ITEM_BIT_SIZE) {}
    T get(size_t index) const {
        size_t bitPos = index * ITEM_BIT_SIZE;
        size_t arrIndex = bitPos / ARRAY_ENTRY_BITS;
        size_t shiftCount = bitPos % ARRAY_ENTRY_BITS;
        return (arr[arrIndex] >> shiftCount) & ITEM_MASK;
    }
    T set(size_t index, T value) {
        size_t bitPos = index * ITEM_BIT_SIZE;
        size_t arrIndex = bitPos / ARRAY_ENTRY_BITS;
        size_t shiftCount = bitPos % ARRAY_ENTRY_BITS;
        value &= ITEM_MASK; // trim
        arr[arrIndex] &= ~(ITEM_MASK << shiftCount); // clear target bits
        arr[arrIndex] |= value << shiftCount; // insert new bits 
        return value;
    }
    ItemMutator operator[](size_t index) {
        return { this, index };
    }
};

Und dann können Sie wie auf ein “Bitfeld” -Array zugreifen:

// create array of some uints
unsigned int arr[5] = { 0, 0, 0, 0, 0 };

// set BitArrayView of 3-bit entries on some part of the array 
// (two indexes starting at 1)
BitArrayView<unsigned int, 3> arrView(arr + 1, 2);

// should equal 21 now => (2 * 32) / 3
arrView.bitSize == 21;

for (unsigned int i = 0; i < arrView.bitSize; i++) {
    arrView[i] = 7; // eg.: 0b111;
}

// now arr[1] should have all bits set
// and arr[2] should have all bits set but last one unset => (2 * 32) % 3 = 1
// the remaining arr items should stay untouched

Dies ist eine einfache Implementierung, die nur mit nicht signierten Sicherungsarrays funktionieren sollte.

Beachten Sie den „Mutator-Trick“ in operator[] ;).

Natürlich könnten auch einige andere Operatoren implementiert werden.

1373780cookie-checkIst es möglich, ein Array von Bitfeldern zu verwenden?

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

Privacy policy