Je suis curieux de savoir, Est-il possible d'utiliser un tableau de champs de bits? Comme:
struct st
{
unsigned int i[5]: 4;
};
Non, tu ne peux pas. Le champ de bits ne peut être utilisé qu'avec des variables de type intégral.
Un champ binaire doit avoir un type qui est une version qualifiée ou non qualifiée de
_Bool
,signed int
,unsigned int
, ou un autre type défini par l'implémentation.
Vous pouvez également le faire
struct st
{
unsigned int i: 4;
} arr_st[5];
mais sa taille sera 5 fois la taille d'un struct
(comme mentionné dans commentaire par @ Jonathan Leffler ) ayant 5 membres chacun avec le champ de bits 4
. Donc, cela n'a pas beaucoup de sens ici.
Vous pouvez le faire de plus près
struct st
{
uint8_t i: 4; // Will take only a byte
} arr_st[5];
C ne prend pas en charge les tableaux de champs binaires, donc la réponse courte est non.
Pour les très grands tableaux, il peut être utile de compresser les valeurs, 2 par octet, de cette façon:
#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);
}
Vous pouvez écrire votre propre classe pour ce cas. Par exemple:
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 };
}
};
Et puis vous pouvez y accéder comme un tableau de "champs de bits":
// 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
Il s'agit d'une implémentation simple qui ne devrait fonctionner qu'avec des matrices de sauvegarde non signées.
Remarquez "l'astuce du mutateur" dans operator[]
;).
Bien sûr, d'autres opérateurs pourraient également être mis en œuvre.