【问题标题】:Weird struct packing奇怪的结构包装
【发布时间】:2016-09-22 19:42:13
【问题描述】:

在处理一些框架结构时,我遇到了一个奇怪的行为。 我很快在独立的示例代码中对其进行了测试,具体如下:

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 个字节,并且填充是以奇怪的方式完成的。我通过为成员变量提供随机值来验证,我观察到填充是在以下 bold locations

完成的

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

【问题讨论】:

  • ptr2-ptr1 绝对等于 6...
  • 在 MSVC 中,如果我将 struct#pragma pack(push, 1)#pragma pack(pop) 括起来,它会给出您预期的结果 5,否则会给出 8。我不得不将void* 指针更改为char*,因为void* 类型上的指针算法是实现定义的。
  • void*s 进行算术的约束违反。您的编译器有义务为此错误发出诊断信息。

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


【解决方案1】:

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

【讨论】:

  • 从 OP 中的粗体十六进制转储开始,我会说位字段是 1 字节对齐的,u 字段是 2 字节对齐的,正如 @987654325 所预期的那样@.
【解决方案2】:

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

C 允许实现在结构元素之间和之后以任意数量和他们选择的任何排列方式插入填充。此外,它没有指定如何将位字段分配给可寻址存储单元,也没有指定分配它们的可寻址存储单元的大小。特别是,就标准而言,位域的声明类型对此一无所知。

因此,最后,您可以计算出表示u 之前的结构成员需要多少位,但您无法计算u 的偏移量应该仅基于什么包含结构的声明。

在实践中,看到u 与结构开头的偏移量相等并不奇怪。因此,结构表示中存在一些填充,但很难确定填充的确切位置,因为您无法获取位域的计算地址。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多