【问题标题】:Create a custom bit fields using a struct使用结构创建自定义位字段
【发布时间】:2022-01-12 21:08:01
【问题描述】:

我正在尝试获取自定义位字段我尝试了这种方法:

struct foo
{   
    unsigned z : 10;
    unsigned y : 16;
    unsigned x : 1;
    unsigned w : 16;
};


int main()
{
    foo test({0x345, 0x1234, 0x1 ,0x1234});
    char bytes[8] = {0};

    std::cout << sizeof(test) << std::endl;

    memcpy(bytes, &test, 8);

    std::cout << sizeof(bool)  << std::endl;

    for (int i = 0; i < sizeof(bytes) / sizeof(char); i++)
    {
        std::cout << std::bitset<8>(bytes[sizeof(bytes) / sizeof(char) - i - 1]);
    }
    std::cout << "" << std::endl;

    return 0;
}

通过我正在尝试的测试,它返回了我:

0000000000000000000100100011010000000100010010001101001101000101

(00000000000000000 | 0010 010 0011 0100 | 000001 | 0001 0010 0011 0100 |11 0100 0101应对应:0x1234 |0x1 | 0x1234 | 0x345)

我从右到左阅读它,在右侧我有10 第一位( 11 0100 0101),然后我有下一个 16 位 (0001 0010 0011 0100)。在该字段之后,我预计下一个数据只需要one 位,但我在最后一个16 位(0001 0010 0011 0100)之前有6 位(000001)而不是(1)。

请问您对此有什么见解吗?

【问题讨论】:

  • 编译器可以随意排序、填充和对齐位域。在这种情况下,您的编译器似乎决定向 x 添加 5 位填充,以便整体结构是 32 位对齐的。
  • 我该如何解决?这是非常奇怪的情况,特别是因为我想在我的位中有一个特定的定义,因为我愿意用它来定义一个硬件消息。
  • Little Endian 也可能会扭曲字节的“预期”视图。但是你想解决什么问题?如果您试图保证特定的位顺序(例如网络协议或总线通信),请编写您自己的序列化(位打包)代码。
  • 您实际上使用位操作运算符,如&lt;&lt;&gt;&gt;|&amp; 将二进制消息打包到字节数组中,而不是依赖编译器来完成工作给你。
  • unsigned char buffer[16] 是 128 位。

标签: c++ c++11 bit-manipulation


【解决方案1】:

您有 5 个备用位,因为下一个位域占用了太多空间,无法放入剩余空间(unsigned 为 8 位)

#include <cstdint> // types with fixed bit sizes

// force to remove padding
#pragma pack(push, 1) 

struct foo
{   
    // make bitsets occupy one address space
    uint32_t z : 10;
    uint32_t y : 16;
    uint32_t x : 1;
    // until now you have 27 bits, another 16 will not fit, 
// thus adding another 5 bits for padding. Nothing you can do.
    uint32_t w : 16; // or you can have uint16_t
    // 
};

#pragma pack(pop)

此外,不同类型的相邻成员的位集can't share address space

【讨论】:

  • 但是没有办法让w5 位中自动“中断”以完成从 27 到 32 的第一部分,而不是使用 5 位填充,然后是 11 w 的以下位完成其余部分?我可以使用联合或其他结构进行硬编码,但我认为它不会是干净的代码。
  • @yacth 您可以在一个字节内放置多个位集(填充 == 1 个字节)。但是您不能将一个位集(小于字节)放在两个字节中。您可以在您的问题中添加消息方案(lsb 到 msb)吗?此外,您可以通过uint32_t : 2 在一个字节内显式添加空位 - 这将在您的位集之间添加 2 位。
  • 我想要以下方案(MSB 在左侧,LSB 在右侧):W= 16 bits | X = 1 bit | Y = 16 bits | Z = 10 bits 如果我理解您告诉我的内容,编译器会将bitset 分组为 32 位,并且由于 X, Y 和 Z 加起来为 27 bits,然后通过添加 5 bits 完成 32 bits,然后写入 W。我想知道我是否可以编写创建结构 struct sW{uint8_t firstFiveBits : 5; uint16_t remainingElevelBits : 11;} 并将 W 声明为 sW 会解决我的问题在这里?
  • 其实这是一个例子,我正在努力更好地了解bitsets,但我的真实数据分为 1 位、32 位、6 位、64 位、16 位、2 位和7 位(MSB → LSB),这些填充问题会更加棘手。
  • 奇怪的是,如果我将每个 bitfield 定义为 uint64_t 它不会做填充。
猜你喜欢
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多