c++ 中位数组中字段的操作

发布于 2024-07-15 03:54:56 字数 644 浏览 2 评论 0原文

所以我想知道设置和操作位字段。

我已经找到 C/C++ 代码来处理字符数组作为位流,这与我的问题类似,我想但它并没有给我一个很好的 stl 方法,我认为它必须存在。

我正在考虑 stl 中的位集,但我的数据集非常复杂1、2、3、4、7、8、16 位格式的位布局。

假设我想访问数据中的一个项目,即第四个字段,它是跨越字节边界的 8 位代码段,有没有一种简单的方法可以做到这一点?

byte 1   byte 2
11112344 44444455

我正在寻找一个好的 stl 实现来访问 4 中的数据或设置 4 中的数据,我假设存在这样的东西,因为必须将数据转移到单个字节并将其屏蔽掉似乎很愚蠢。 编写它似乎也很困难,并且应该有一种更简单的方法来完成这样的任务。

还有别的办法吗?

编辑 - 我的数据集长度约为 20 个字节,我想将其全部按位顺序保存

So I'm wondering about both setting and manipulating bit fields.

I've already found C/C++ Code to treat a character array as a bitstream which is similar to my question I guess but it doesn't doesn't give me a nice stl approach I am thinking has to exist.

I was thinking of bitsets from the stl but my data set is very complex with bit layouts of 1,2,3,4,7,8,16 bit formats.

Lets say I wanted to access an item in my data, the 4th field which is a 8 bit segment of code that crosses a byte boundry, is there an easy way to do this?

byte 1   byte 2
11112344 44444455

I'm looking for a good stl implementation to access the data in 4 or set the data in 4, I assume something exists for this as it seems silly to have to shift the data into a single byte and mask it off. writing it also seems difficult and like there should be an easier way to accomplish such a task.

Is there another way?

edit - my data set is around 20 bytes in length and i want to keep it all in bit order

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

丿*梦醉红颜 2024-07-22 03:54:56

您能解释一下为什么常规位域不够吗? 换句话说,为什么不这样做:

    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;

做你想做的事?

您是否希望能够以编程方式动态构建不同的布局或其他什么?

Can you explain why regular bitfields are insufficient? In other words why doesn't this:

    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;

do what you want?

Is it that you want to be able to programmatically construct different layouts on the fly or something?

弥繁 2024-07-22 03:54:56

无论您添加任何语法糖,掩蔽和转换都会发生。 如果您想让事情变得非常易于使用,但首先有点难做,您可以使用一个类,以及一些宏/模板代码,以使定义新类变得更容易:

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();

如果你的字段超出了支持字段的范围,你将得到一个编译时断言。 不会检查字段是否重叠,因此您必须注意这一点。

The masking and shifting is going to happen regardless of any syntactic sugar you add. If you want to make things really easy to use, but a little harder to make in the first place, you can use a class, along with a bit of macro/template code to make it a little easier to define new 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;
};

Then define your class like this:

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

Usage:

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

You'll get a compile time assert if your fields fall outside of the range of the backing fields. There is no checking that fields don't overlap, so you'd have to watch out for that.

山川志 2024-07-22 03:54:56

看起来现有的类(例如 vectorBoost.DynamicBitset)不会为您做任何事情。

底层的实现将不得不进行移位和屏蔽,这并不愚蠢。 使用底层 vectorvector 编写自己的类或模板并不难,然后您就可以优化移位/屏蔽代码以实现什么目的你认为你的要求是,比如:

  • 这是随机访问还是顺序访问? (如果它是连续的,那么您可以避免对移位掩码进行一些重新计算。)
  • 所有元素的大小是否相同,或者您是否以任意位偏移量索引任意大小的元素?

It does appear that the existing classes such as vector<bool> or Boost.DynamicBitset aren't going to do anything for you.

The underlying implementation is going to have to do shifting and masking, nothing silly about that. Writing your own class or template using an underlying vector<bool> or vector<something_else> isn't that hard and then you get to optimize the shifting/masking code for what you think your requirements are, such as:

  • Is this random access or sequential? (If it's sequential then you can avoid some recomputation of your shifted-around masks.)
  • Are all elements the same size or are you indexing arbitrary-size elements at arbitrary bit-offsets?
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文