如何使用struct和bitfields来确保精确的位顺序

时间:2016-02-29 18:09:46

标签: c++ qt struct padding bit-fields

我一直在搜索这个话题,我希望最终得到答案。

我想使用特定硬件的结构,我想在C中实现它;这是我想要的包:

typedef struct {
    quint8 startByte        :8;
    quint16 ch1             :11;
    quint16 ch2             :11;
    quint16 ch3             :11;
    quint16 ch4             :11;
    quint16 ch5             :11;
    quint16 ch6             :11;
    quint16 ch7             :11;
    quint16 ch8             :11;
    quint16 ch9             :11;
    quint16 ch10            :11;
    quint16 ch11            :11;
    quint16 ch12            :11;
    quint16 ch13            :11;
    quint16 ch14            :11;
    quint16 ch15            :11;
    quint16 ch16            :11;
    quint8 endByte1         :8;
    quint8 endByte          :8;
}packet;

如果计算大小,则为25个字节。但是当我使用sizeof(packet)时,我得到46。 现在我正在使用Qt 5.5,我也想在Atmel工作室7中使用此代码和AVR。 顺便说一下,我也使用了#pragma pack(1)__attribute__((__packed__)),并使sizeof(packet)等于35。

1 个答案:

答案 0 :(得分:2)

你有16个短路* 2个字节= 32个字节+起始字节+两个结束字节 - 如果它是打包的,总共35个字节。由于您对11位字段使用16位数据类型,因此只剩下5个字节 - 您不能将11位字段装入5位,因此这5位基本上是浪费的。

0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
| field 1 |xxxxx| field 2 |xxxxx| field 3 |xxxxx

如果我理解正确,你想要达到的目标更像是:

0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
| field  1 | field  2 | field  3 | field  4 |...

我不确定编译器是否可以为您生成这样的布局,但是如评论中已经提到的那样,您可以手动执行此操作。编译器没有这样做,因为它效率很低 - 为了读取跨越边界的字段,你必须做两次读取,掩码,移位和组合最终结果。

我已经链接的答案详细解释了位操作,这里唯一不同的是你将跨越边界。

| byte1 | byte2 | byte3 | byte4 |
0123456701234567012345670123456701
| field  1 | field  2 | field  3 |

例如,您想要读取字段2 - 它的索引是1,因此1 * 11 = 11 - 这是字段的位偏移量。 11/8 = 1,余数为3.这意味着它的值在第二个字节的第3位之后开始,占据8-3 = 5位,11-5 =下一个字节的6位。我们假设字段值为00100110111

| byte1 | byte2 | byte3 | byte4 |
0123456701234567012345670123456701
| field  1 | field  2 | field  3 |
        xxx00100110111xx

该值将包含在两个字节xxx00100110111xx内,并且可以通过移动和组合这两个字段来重建它:

xxx00100          << 8 AND
        110111xx
xxx00100110111xx

然后将其向左移3以切断前一个字段的前3位,然后将其右移3 + 2以切断下一个字段的最后2位,并留下0000000100110111这是短期内该领域的价值。

为了编写字段,过程类似,但是,请确保不要破坏相邻字段中的位 - 您需要保存,然后在为目标字段写入字节时正确恢复这些位。 / p>