【问题标题】:64-bit structure is actually padded to 12 bytes64位结构实际上填充到12字节
【发布时间】:2021-10-06 20:59:58
【问题描述】:

考虑下面的结构,其中位域大小的总和为 64 位。为什么sizeof 说这个结构是 12 字节,而应该是 8 字节?

typedef struct wl_Ls {
    unsigned int    total:17;
    unsigned int    used:17;
    unsigned int    entrySize:17;
    _Bool           point:1;
} wl_Ls;

[解决方案:] 使用 64 位类型修复前 2 或 3 个成员修复它。解释在标记为解决方案的答案中

【问题讨论】:

  • sizeof 对该架构中的各个元素有何看法?
  • 如果将point_Bool 更改为unsigned int,会发生什么情况? IIRC,相邻的位域需要有匹配的类型。
  • 17+17 不适合 unsigned int。试试uint64_t
  • 我怀疑这是为每个成员设置单词地址的方式。请参阅以下内容进行讨论:catb.org/esr/structure-packing/#_bitfields
  • @Wispy:我认为这个想法是uint64_t total:17; uint64_t used:17; 等等。不需要逻辑运算。

标签: c memory struct sizeof bit-fields


【解决方案1】:

并不总是保证位域紧密地打包在一起。允许编译器在位域之间插入填充的两种情况是:当两个连续的位域不是同一类型时,以及当位域不适合在“分配单元”中仍然可用的位数时位域的类型。

假设 unsigned int 是 32 位,则结构中的所有三对连续位域都符合这些情况中的至少一种。

【讨论】:

  • 如果我要删除 point 成员,它仍然会分配 12 个字节,至少在带有 GCC 的 Unix 系统上是这样。在这种情况下,“分配单元”应该是 8 个字节,不是吗?如果没有,是否为位域分配了一些额外的字节?
  • @Wispy 每个成员为 4 个字节。
  • 它不能将两个 17 位字段组合成同一个 unsigned int。所以它必须为每个成员使用单独的unsigned int。 3x4 = 12 字节。
  • C 标准在声明位域的类型和存储单元之间没有强加任何关系。无论unsigned int 是否为 32 位,C 实现都可以为 17 位位字段分配任何 17 位或更大的可寻址存储单元。当连续的位域被声明为不同的类型时,它也没有说可以插入填充(可以跳过位)。它说如果存储单元中有足够的空间,则将以下位字段打包到该单元中,并且没有提及类型(C 2018 6.7.2.1 11)。
  • @EricPostpischil 如果没记错的话,这是相对于某些旧版标准的更改。不过,目前无法告诉您哪个旧版本。
猜你喜欢
  • 2016-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-09
  • 1970-01-01
  • 2018-08-28
  • 2016-01-13
  • 2017-07-24
相关资源
最近更新 更多