【问题标题】:Bit field vs Bitset位域与位集
【发布时间】:2023-03-17 05:49:01
【问题描述】:

我想将位存储在数组中(如结构)。所以我可以遵循以下两种方法中的任何一种

方法 1 (AN 1)

struct BIT
{
   int data : 1
};

int main()
{
   BIT a[100];
   return 0;
}

方法 2 (AN 2)

int main()
{
    std::bitset<100> BITS;
    return 0;
}

为什么有人更喜欢 AN 2 而不是 AN 1?

【问题讨论】:

  • 引用 cplusplus.com 在 bitset 上的页面,“该类与常规数组非常相似,但针对空间分配进行了优化”。如果您的整数是 4 个字节,那么位集使用的空间将减少 32 倍。
  • 你的结构 BIT 无论如何都会对齐到(至少)一个字节。
  • @Jon,将其发布为答案。 (这是一个很好的观点。)
  • @sbi 大多数实现都有 >= 1 字节的布尔值,所以 bitset 的效率仍然是 8 倍。
  • 还需要说明的是,根据你的使用方式,AN1在使用更多内存的同时,访问时间也比AN2快。我说取决于如果数组很大,由于 CPU 缓存内存,bitset/vector 版本可能仍然更快。

标签: c++ bit-fields bitset


【解决方案1】:

因为接近 nr。 2 实际上使用 100 位存储,加上一些非常小的(恒定)开销,而 nr. 1 通常每个Bit 结构使用四个字节的存储空间。通常,根据 C++ 标准,struct 至少大一个字节。

#include <bitset>
#include <iostream>

struct Bit { int data : 1; };

int main()
{
    Bit a[100];
    std::bitset<100> b;
    std::cout << sizeof(a) << "\n";
    std::cout << sizeof(b) << "\n";
}

打印

400
16

除此之外,bitset 将您的位数组包装在一个带有许多有用操作的漂亮对象表示中。

【讨论】:

  • sizeof(b)的输出怎么是16? 100 位表示 100/8 字节。我错过了什么?
  • 它必须“四舍五入”到八的倍数,因为字节是可直接寻址的最小存储单元。尝试在集合中使用 128 位进行编译,然后它仍然是 16。bitset 使用了一些技巧来假装它实际上是在寻址位..
  • 我之前的评论说对了一半。它向上取整为 4 字节的倍数,因为对于 32 位计算机来说,4 字节单元的处理速度最快。但无论如何,一个字节是最小的可寻址单元,所以它至少是13(100/8 = 12.5,半个字节是不可寻址的)。抱歉,星期五下午。
【解决方案2】:

一个好的选择取决于你将如何使用这些位。

std::bitset&lt;N&gt; 是固定大小的。 Visual C++ 10.0 不符合标准。给构造函数;一般来说,您必须提供一种解决方法。具有讽刺意味的是,这是由于微软认为是一个错误修复——我记得他们引入了一个带有 int 参数的构造函数。

std::vector&lt;bool&gt; 的优化方式与std::bitset 大致相同。成本:索引不直接提供引用(在 C++ 中没有对单个位的引用),而是返回一个代理对象——除非您尝试将其用作引用,否则您不会注意到它。优点:最小的存储空间,并且可以根据需要调整向量的大小。

只需使用例如unsigned 也是一个选项,如果您要处理少量位(实际上,32 或更少,虽然正式保证只有 16 位)。

最后,ALL UPPERCASE 标识符按照惯例(Microsoft 除外)为宏保留,以减少名称冲突的可能性。因此,最好不要将所有大写标识符用于宏以外的任何内容。并且始终对宏使用全部大写的标识符(这也使得它们更容易识别)。

干杯,

【讨论】:

    【解决方案3】:

    bitset 有more operations

    【讨论】:

      【解决方案4】:

      方法 1 很可能被编译为一个 4 字节整数数组,每个整数的一位将用于存储您的数据。从理论上讲,智能编译器可以对此进行优化,但我不会指望它。

      您是否有不想使用std::bitset 的原因?

      【讨论】:

        【解决方案5】:

        引用cplusplus.com's page on bitset,“该类与常规数组非常相似,但针对空间分配进行了优化”。如果您的 int 是 4 个字节,那么 bitset 使用的空间将减少 32 倍。

        即使像 sbi 建议的那样做 bool bits[100],仍然比 bitset 差,因为大多数实现都有 >= 1 字节的布尔值。

        如果仅出于求知欲的原因,您想实现自己的位集,则可以使用位掩码:

        typedef struct {
          unsigned char bytes[100];
        } MyBitset;
        
        bool getBit(MyBitset *bitset, int index)
        {
          int whichByte = index / 8; 
          return bitset->bytes[whichByte] && (1 << (index = % 8));
        }
        
        bool setBit(MyBitset *bitset, int index, bool newVal)
        {
          int whichByte = index / 8;
        
          if (newVal)
          {
            bitset->bytes[whichByte] |= (1 << (index = % 8));
          }
          else
          {
            bitset->bytes[whichByte] &= ~(1 << (index = % 8));
          }
        }
        

        (对不起,顺便说一下,使用结构而不是类。我正在考虑直接 C,因为我正在为学校做一个低级作业。显然,使用类的两个巨大好处是运算符重载和拥有可变大小数组的能力。)

        【讨论】:

        • 在c++中,类和结构的唯一区别是类成员默认是私有的,结构成员默认是公有的。
        猜你喜欢
        • 1970-01-01
        • 2020-05-10
        • 1970-01-01
        • 2019-11-19
        • 1970-01-01
        • 2013-10-04
        • 2019-10-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多