奇怪的结构包装

时间:2016-09-22 19:42:14

标签: c struct memory-alignment bit-fields packing

在处理某些帧结构时,我遇到了一种奇怪的行为。 我快速测试了它和独立的示例代码,如下:

struct non_alligned_struct
{
    uint8_t  flag;

    // start of uint32 bit fields
    uint32_t a:2;
    uint32_t b:2;
    uint32_t c:1;
    uint32_t d:1;
    uint32_t e:1;
    uint32_t f:1;
    uint32_t g:3;
    uint32_t h:1;
    uint32_t i:1;
    uint32_t j:3;
    uint32_t k:3;
    uint32_t l:1;
    uint32_t m:1;
    uint32_t n:1;
    uint32_t o:1;
    uint32_t p:3;
    uint32_t q:2;
    uint32_t r:1;
    uint32_t s:1;
    uint32_t t:2;
    //4 bytes ends here

    // shouldn't this start at 5th byte ??
    uint16_t u;

    uint16_t v:13;
    uint16_t w:3;

    uint16_t x;

    uint16_t y:13;
    uint16_t z:3;
};

int main()
{
    struct non_alligned_struct obj1;
    void *ptr1 = &obj1;
    void *ptr2 = &(obj1.u);
    printf("ptr1: %p, ptr2: %p, ptr2 - ptr1: %d\n", ptr1, ptr2, ptr2 - ptr1);
    return 0;
}

输出: ptr1:0x7fff3216a620,ptr2:0x7fff3216a626,ptr2 - ptr1:6

问题:为什么ptr2-ptr1应该是6.根据我的计算它应该是5.而且结构是13个字节,所以它得到4个字节对齐并且填充以奇怪的方式完成。我通过给成员变量提供随机值来验证,我发现填充是在以下粗体位置

完成的

00000000:01 22 31 10 67 00 fe ff 86 01 fe ff 86 01 00 00

2 个答案:

答案 0 :(得分:1)

位字段的对齐是实现定义的。您的实现似乎对uint32_t字段使用1或(可能2)字节对齐。结果,flag占用字节0,并且位字段占用字节1..4或2..5。在前一种情况下,u默认为2字节对齐,将其置于字节6..7,而在后一种情况下,6..7已经是下一个可用的插槽。

答案 1 :(得分:1)

  

问题:为什么ptr2-ptr1应为6.根据我的计算,它应该是5。

C允许实现在struct元素之间和之后以任何数量和任何排列方式插入填充。另外,它没有规定如何将位字段分配给可寻址存储单元,也不指定它们被分配到的可寻址存储单元的大小。特别是,就标准而言,声明的位域类型对此没有任何说明。

因此,最后,您可以计算在u之前表示结构成员所需的位数,但无法计算u的偏移量仅基于包含结构的声明。

在实践中,将u定位在距离结构开始的均匀偏移处并不奇怪。接下来在结构表示中有一些填充,但是很难确定填充的确切位置,因为你不能获取位域的计算地址。