【问题标题】:Bitfield using 1 byte instead of 1 bit位域使用 1 个字节而不是 1 个位
【发布时间】:2021-07-22 06:10:34
【问题描述】:

我正在开发一个网络应用程序,我将在其中接收 2 个字节,并且某些位具有特定意义。我正在尝试将该数据包实现为一个结构。目的是对对象地址进行二进制复制,并且可以访问数据包的字段。这是一个代表我的问题的简单示例。当我们尝试检查位域和结构的大小时,它们并没有像预期的那样出现。

#include <bitset>
#include<iostream>
struct a
    {
        std::bitset<8> b;
        uint8_t c;

    };
int main()
{
    std::cout<<sizeof(a);
}

输出:8

预期输出:2

这是特定于 Bitset 实现的东西吗?

通常,每个元素只占用一位(在大多数系统上,它比最小的元素类型:char 少八倍)。 (参考-cplusplus.com/reference/bitset/bitset/)

在 Microsoft Visual Studio 2019 16.10.2 上编译

【问题讨论】:

  • 我希望 std::bitset 有一个更明智的实现...您可以使用另一个 uint8_t,或者使用实际的位域,例如uint8_t foo:1, bar:1;.
  • 问题是由于某种原因sizeof(std::bitset&lt;8&gt;) == 8,它与godbolt.org/z/Mhd1n7TYK类无关。也许是因为效率,在某些系统中使用底层 8 字节类型实现 8 位(甚至更少)操作可能会更快?好消息是sizeof(std::bitset&lt;64&gt;) == 8 而不是 64。

标签: c++ bit-fields


【解决方案1】:

微软Visual Studio的STL源代码最近开源了,可以查看bitsethere的实现,可以确认数据结构是array,草图:

template <size_t _Bits>
class bitset { // store fixed-length sequence of Boolean elements
public:
    using _Ty = conditional_t<_Bits <= sizeof(unsigned long) * CHAR_BIT, unsigned long, unsigned long long>;
    static constexpr ptrdiff_t _Bitsperword = CHAR_BIT * sizeof(_Ty);
    static constexpr ptrdiff_t _Words       = _Bits == 0 ? 0 : (_Bits - 1) / _Bitsperword; // NB: number of words - 1
    _Ty _Array[_Words + 1];
};

所以对于std::bitset&lt;8&gt;,底层数组是unsigned long _Array[1]。然后我们得到大小:4。sizeof struct a 的结果是 8,这是由于 bc 周围的对齐造成的,请参阅此answer 以获取有关对齐的参考。

由于您是在处理网络应用程序,所以这里不适合使用 bitset。要解码网络协议,最好使用位域。 seastar的tcp decoder有一个很好的例子,你可以拿来做例子。

【讨论】:

  • sizeof(unsigned long) 在微软的编译器中是 4 个字节,而不是 8 个字节。额外的字节更有可能来自对齐填充。该结构需要设置为 1 字节对齐以消除填充。
  • @RemyLebeau 感谢您的精彩评论!我只是忘记了 Gcc 和 VC++ 之间的区别。我现在已经更新了答案。
  • 对齐填充更有可能出现在c 字段之后,而不是bc 字段之间。您可以使用offsetof(a::c) 进行验证。
  • @RemyLebeau 我已经确认填充在 c 字段之后!感谢您提供这么多很棒的建议!
猜你喜欢
  • 2013-05-10
  • 2017-02-24
  • 2014-12-15
  • 2019-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-24
相关资源
最近更新 更多