манипулирование полями в массиве битов в c ++ - PullRequest
1 голос
/ 17 марта 2009

Так что мне интересно как устанавливать битовые поля и управлять ими.

Я уже нашел Код C / C ++ для обработки массива символов как потока битов , который похож на мой вопрос, я думаю, но это не дает мне хороший подход stl. мышление должно существовать.

Я думал о битовых наборах из stl , но мой набор данных очень сложный с разметкой битов в 1,2,3,4,7,8,16 битных форматах.

Допустим, я хотел получить доступ к элементу в моих данных, 4-е поле, представляющее собой 8-битный сегмент кода, пересекающий границу байта, есть ли простой способ сделать это?

byte 1   byte 2
11112344 44444455

Я ищу хорошую реализацию stl для доступа к данным в 4 или для установки данных в 4, я предполагаю, что для этого что-то существует, так как глупо смещать данные в один байт и маскировать их. его написание также кажется трудным, и как будто должен быть более легкий способ выполнить такую ​​задачу.

Есть ли другой способ?

edit - мой набор данных имеет длину около 20 байтов, и я хочу сохранить все это в битовом порядке

Ответы [ 3 ]

1 голос
/ 17 марта 2009

Маскирование и сдвиг произойдут независимо от того, какой синтаксический сахар вы добавите. Если вы хотите сделать вещи действительно простыми в использовании, но вначале их немного сложнее, вы можете использовать класс вместе с небольшим количеством кода макроса / шаблона, чтобы немного упростить определение новых классов: *

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

Тогда определите свой класс следующим образом:

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

Использование:

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

Вы получите подтверждение времени компиляции, если ваши поля выходят за пределы диапазона вспомогательных полей. Нет проверки того, что поля не перекрываются, поэтому вам следует следить за этим.

1 голос
/ 17 марта 2009

Можете ли вы объяснить, почему обычные битовые поля недостаточны? Другими словами, почему это не так:

    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;

делай что хочешь?

Вы хотите иметь возможность программно создавать различные макеты на лету или что-то в этом роде?

0 голосов
/ 17 марта 2009

Похоже, что существующие классы, такие как vector<bool> или Boost.DynamicBitset, ничего не сделают для вас.

Базовая реализация должна будет выполнять сдвиг и маскировку, в этом нет ничего глупого. Написание собственного класса или шаблона с использованием базовых vector<bool> или vector<something_else> не так сложно, и тогда вы можете оптимизировать код сдвига / маскировки для того, что, по вашему мнению, соответствует вашим требованиям, например:

  • Это произвольный доступ или последовательный? (Если это последовательно, то вы можете избежать некоторого пересчета ваших сдвинутых масок.)
  • Все ли элементы имеют одинаковый размер или вы индексируете элементы произвольного размера с произвольными смещениями?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...