2009-03-17 8 views
1

Je m'interroge à la fois sur la définition et la manipulation des champs de bits.manipulation de champs dans un tableau de bits en C++

J'ai déjà trouvé C/C++ Code to treat a character array as a bitstream ce qui est similaire à ma question je suppose mais ça ne me donne pas une belle approche stl je pense qu'il doit exister.

Je pensais à des bitsets du stl mais mon ensemble de données est très complexe avec des mises en page bit de formats 1,2,3,4,7,8,16 bits. Disons que je voulais accéder à un élément dans mes données, le 4ème champ qui est un segment de 8 bits de code qui traverse une limite d'octets, y at-il un moyen facile de faire cela?

byte 1 byte 2 
11112344 44444455 

Je cherche une bonne mise en œuvre de stl pour accéder aux données de 4 ou définir les données 4, je suppose existe quelque chose pour cela comme il semble stupide d'avoir à déplacer les données dans un seul octet et le masquer. écrire cela semble aussi difficile et comme il devrait y avoir un moyen plus facile d'accomplir une telle tâche.

Existe-t-il un autre moyen?

modifier - mon ensemble de données est d'environ 20 octets de longueur et je veux tout garder en ordre peu

Répondre

1

Pouvez-vous expliquer pourquoi bitfields courant sont insuffisants? En d'autres termes, pourquoi ne pas cela:

struct ComplexBitLayout { 
     unsigned field1 :4; 
     unsigned field2 :1; 
     unsigned field3 :1; 
     unsigned field4 :8; 
     unsigned field5 :2; 
    } __attribute__((__packed__)); // or your compiler's equivalent 

    ComplexBitLayout cbl; 

    cbl.field4 = x; 

faites ce que vous voulez?

Est-ce que vous voulez pouvoir créer par programmation différentes configurations à la volée?

+0

Il est tentant d'utiliser des champs de bits, mais ils ne sont pas portables, ce qui peut souvent être le dealbreaker. –

+0

c'est ce que je cherche, bien que, comme Brian l'a dit, pas portable, et ne fonctionne pas avec mon OS –

1

Le masquage et le décalage vont se produire indépendamment du sucre syntaxique que vous ajoutez. Si vous voulez rendre les choses vraiment faciles à utiliser, mais un peu plus difficile à faire en premier lieu, vous pouvez utiliser une classe, avec un peu de code macro/template pour faciliter la définition de nouvelles classes:

template<bool> struct CompileTimeAssert; 
template<> struct CompileTimeAssert<true> { }; 

#define ASSERT(check) if (!check) throw exception("Assertion Failure" #check) 

#define ADDBITVALUE(backingField, backingFieldType, fieldName, offset, size) \ 
    public: \ 
    static const unsigned int fieldName##Offset = offset; \ 
    static const backingFieldType fieldName##Mask = CalculateMask<offset, size, backingFieldType>::Value; \ 
    public: \ 
    void Set##fieldName(backingFieldType value) \ 
    {\ 
     ASSERT(("Value too large for field.", (value & (fieldName##Mask >> fieldName##Offset)) == value));\ 
     backingField |= value << fieldName##Offset;\ 
    }\ 
    backingFieldType Get##fieldName() const\ 
    {\ 
     return (backingField & fieldName##Mask) >> fieldName##Offset;\ 
    }\ 
    private: 

#define ADDSPANNEDVALUE(backingField1, backingField1Type, backingField2, backingField2Type, fieldName, offset1, size1, offset2, size2)\ 
    ADDBITVALUE(backingField1, backingField1Type, fieldName##internal1, offset1, size1)\ 
    ADDBITVALUE(backingField2, backingField2Type, fieldName##internal2, offset2, size2)\ 
    public: \ 
    void Set##fieldName(backingField1Type value) \ 
    {\ 
     backingField1Type value1 = value << (sizeof(backingField1Type)*8-size1);\ 
     value1 = value1 >> (sizeof(backingField1Type)*8-size1);\ 
     Set##fieldName##internal1(value1);\ 
     Set##fieldName##internal2(value >> size1);\ 
    }\ 
    backingField1Type Get##fieldName() const\ 
    {\ 
     return Get##fieldName##internal1() | (Get##fieldName##internal2() << size1);\ 
    }\ 
    private: 

template <unsigned int Offset, int Size, typename T> 
struct CalculateMask 
{ 
    CompileTimeAssert<(Size > 0)> Object; 
    static const T Value = (T)((1 << Offset) | CalculateMask<Offset + 1, Size - 1, T>::Value); 
}; 

template <unsigned int Offset, typename T> 
struct CalculateMask<Offset, 0, T> 
{ 
    CompileTimeAssert<(Offset <= sizeof(T) * 8)> Object; 
    static const T Value = 0; 
}; 

Définissez ensuite votre classe comme ceci:

class BitGroup 
{ 
    unsigned short Values; 
    unsigned short Values2; 
    ADDBITVALUE(Values, unsigned short, Field1, 0, 12); 
    ADDSPANNEDVALUE(Values, unsigned short, Values2, unsigned short, Field2, 12, 4, 0, 2); 
    ADDBITVALUE(Values2, unsigned short, Field3, 2, 14); 
public: 
    BitGroup() : Values(0), Values2(0) {} 
}; 

Utilisation:

BitGroup bg; 
bg.SetField1(15); 
cout << bg.GetField1(); 
bg.SetField2(63); 
cout << bg.GetField1(); 

Vous obtiendrez une compilation si vos champs affirment ne relèvent pas de la plage des champs d'appui. Il n'y a pas de vérification que les champs ne se chevauchent pas, donc vous devriez faire attention à cela.

+0

cela fonctionnerait-il par exemple 216 bits? on dirait que c'est une solution pour 16 bits –

+0

Vous seriez bloqué à 64 bits pour le plus grand champ. – Eclipse

+0

Qu'est-ce qu'un "long short"? Ne définit-il pas des valeurs constantes à quoi servent les enums? –

0

Il semble que les classes existantes telles que vector<bool> ou Boost.DynamicBitset ne feront rien pour vous.

La mise en œuvre sous-jacente va devoir faire le changement et le masquage, rien d'idiot à ce sujet. La rédaction de votre propre classe ou un modèle en utilisant un sous-jacent vector<bool> ou vector<something_else> est pas difficile et vous obtenez pour optimiser le code décalage/masquage pour ce que vous pensez que vos besoins sont, par exemple:

  • Est-ce un accès aléatoire ou séquentiel? (Si c'est séquentiel alors vous pouvez éviter un recalcul de vos masques décalés.
  • Tous les éléments ont-ils la même taille ou indexez-vous des éléments de taille arbitraire à des décalages de bits arbitraires?
Questions connexes