具有别名的可变大小位域

发布于 2024-08-06 12:47:00 字数 1056 浏览 2 评论 0原文

我有一些包含位字段的结构,其大小可能有所不同。示例:

struct BitfieldSmallBase {
    uint8_t a:2;
    uint8_t b:3;
    ....
}

struct BitfieldLargeBase {
    uint8_t a:4;
    uint8_t b:5;
    ....
}

和一个联合一次访问所有位:

template<typename T>
union Bitfield 
{
    T bits;
    uint8_t all;    // <-------------  Here is the problem

    bool operator & (Bitfield<T> x) const {
        return !!(all & x.all);
    }
    Bitfield<T> operator + (Bitfield<T> x) const {
        Bitfield<T> temp;
        temp.all = all + x.all;   //works, because I can assume no overflow will happen
        return temp;
    }
    ....
}

typedef Bitfield<BitfieldSmallBase> BitfieldSmall;
typedef Bitfield<BitfieldLargeBase> BitfieldLarge;

问题是:对于某些位域基类,uint8_t 是不够的。 BitfieldSmall 确实适合 uint8_t,但 BitfieldLarge 则不适合。数据需要尽可能紧密地打包(稍后将由 SSE 指令处理),因此始终使用 uint16_t 是没有问题的。有没有办法用整型声明“all”字段,其大小与位字段相同?或者另一种访问整个位的方法?

我当然可以放弃使用模板并显式声明每种位字段,但我想避免代码重复(有相当多的运算符和成员函数列表)。

I have some struct containig a bitfield, which may vary in size. Example:

struct BitfieldSmallBase {
    uint8_t a:2;
    uint8_t b:3;
    ....
}

struct BitfieldLargeBase {
    uint8_t a:4;
    uint8_t b:5;
    ....
}

and a union to access all bits at once:

template<typename T>
union Bitfield 
{
    T bits;
    uint8_t all;    // <-------------  Here is the problem

    bool operator & (Bitfield<T> x) const {
        return !!(all & x.all);
    }
    Bitfield<T> operator + (Bitfield<T> x) const {
        Bitfield<T> temp;
        temp.all = all + x.all;   //works, because I can assume no overflow will happen
        return temp;
    }
    ....
}

typedef Bitfield<BitfieldSmallBase> BitfieldSmall;
typedef Bitfield<BitfieldLargeBase> BitfieldLarge;

The problem is: For some bitfield base classes, an uint8_t is not sufficient. BitfieldSmall does fit into a uint8_t, but BitfieldLarge does not. The data needs to be packed as tightly as possible (it will be handled by SSE instructions later), so always using uint16_t is out of question. Is there a way to declare the "all" field with an integral type, whose size is the same as the bitfield? Or another way to access bits as a whole?

I can of course forego the use of the template and declare every kind of bitfield explicitly, but I would like to avoid code repetition (there is quite a list of operators und member functions).

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

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

发布评论

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

评论(6

2024-08-13 12:47:01

您可以使用模板元编程来定义一个模板函数,该函数从 BitfieldSmallBase、BitfieldLargeBase 等映射到另一种类型 - 默认情况下为 uint8_t,并为 BitfieldLargeBase 映射到 uint16_t 作为模板专业化,然后像这样使用它:

union Bitfield 
{
    T bits;
    typename F<T>::holder_type all;
};

you can use template metaprogramming to define a template function that maps from BitfieldSmallBase, BitfieldLargeBase, etc into another type - uint8_t by default and to uint16_t for BitfieldLargeBase as a template specialization and then use that like this:

union Bitfield 
{
    T bits;
    typename F<T>::holder_type all;
};
心不设防 2024-08-13 12:47:01

您可能需要考虑 std::bitsetboost::dynamic_bitset 而不是自己滚动。无论如何,避开std::vector

You might want to consider std::bitset or boost::dynamic_bitset rather than rolling your own. In any case, steer clear of std::vector<bool>!

这个俗人 2024-08-13 12:47:01

将所需的字节数作为模板参数的一部分:

template <typename T, int S=1>
struct BitField 
{
   union
   {
      T bits;
      unsigned char bytes[S];
   };
};

typedef Bitfield<BitfieldSmallBase, 1>  BitfieldSmall;
typedef Bitfield<BitfieldLargeBase, 2> BitfieldLarge;

Make the number of bytes you need part of the template parameters:

template <typename T, int S=1>
struct BitField 
{
   union
   {
      T bits;
      unsigned char bytes[S];
   };
};

typedef Bitfield<BitfieldSmallBase, 1>  BitfieldSmall;
typedef Bitfield<BitfieldLargeBase, 2> BitfieldLarge;
旧时模样 2024-08-13 12:47:01

这个怎么样?

#include <limits.h>

template <class T>
union BitField
{
    T bits;
    unsigned all : sizeof(T) * CHAR_BIT;
};

How about this?

#include <limits.h>

template <class T>
union BitField
{
    T bits;
    unsigned all : sizeof(T) * CHAR_BIT;
};
断爱 2024-08-13 12:47:00

您也可以将整数类型设置为模板参数。

template<typename T, typename U>
union Bitfield 
{
    T bits;
    U all;
}

typedef Bitfield<BitfieldSmallBase, uint8_t>  BitfieldSmall;
typedef Bitfield<BitfieldLargeBase, uint16_t> BitfieldLarge;

You could make the integral type a template parameter as well.

template<typename T, typename U>
union Bitfield 
{
    T bits;
    U all;
}

typedef Bitfield<BitfieldSmallBase, uint8_t>  BitfieldSmall;
typedef Bitfield<BitfieldLargeBase, uint16_t> BitfieldLarge;
木森分化 2024-08-13 12:47:00

我经历了惨痛的教训,虽然您使用的变量上的位宽度是让编译器为您进行掩码和移位的便捷方法,但您不能对顺序做出假设以及结构中成员的填充。它依赖于编译器,编译器确实改变了顺序,这依赖于项目中的其他代码。

如果你想将一个字节视为离散字段,你真的必须以困难的方式做到这一点。

I've learnt the hard way that whilst the bit width on vars that you're using is a convenient way of getting the compiler to do your masking and shifting for you, you cannot make assumptions about the order and padding of the members in the struct. Its compiler dependent and the compiler really does change the order and such dependent upon the other code in your project.

If you want to treat a byte as discrete fields, you really have to do it the hard way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文