【问题标题】:Sizeof of packed structure with bit fields带有位域的打包结构的大小
【发布时间】:2020-03-20 10:41:47
【问题描述】:

考虑这段代码:

#include <stdio.h>
#include <stdint.h>

#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif

#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop))
#endif

PACK(struct S
{
  uint8_t  f0;
  uint32_t f1;
  uint32_t f2 : 17;
});

int main()
{
    printf("%zu\n", sizeof(struct S));
    return 0;
}

没有给出编译器选项。

输出:

gcc   (9.2.0): 8
clang (8.0.1): 8
cl    (19.23.28106.4 for x86): 9

为什么在cl 的情况下sizeof 的结果是9?

标准是怎么说的?

【问题讨论】:

  • 恕我直言,唯一正确的是cl 的输出。可能其他两个优化器太谨慎了...尝试为结构分配值并在函数中使用它们来强制编译器实现正确的空间。
  • 人们倾向于对位域语义和表示做出比 C 语言规范支持的更多的假设。也可以添加一些扩展,例如结构包装,你最好抓住你的帽子。
  • @Frankie_C Clang 和 GCC 位包,即它们只存储使用的字节。 MSVC 可能只有字节包结构。
  • @S.S.Anne 我环顾四周,似乎storage unit 的不同解释是:对于 GCC/CLANG,它是基本内存单元(在这种情况下是 8 位字节),对于 MS它是用于位域说明符的最后一种类型。所以两者都符合C标准。

标签: c sizeof bit-fields packed


【解决方案1】:

C 标准 C17 6.7.2.1/11 说,强调我的:

一个实现可以分配任何足够大的可寻址存储单元来保存一个位域。如果有足够的空间剩余,一个紧跟在结构中另一个位域之后的位域应该被打包到相邻的位中属于同一单位。如果剩余空间不足, 不适合的位域是否放入下一个单元或与相邻单元重叠是 实现定义。一个单元内位域的分配顺序(高位到 低阶或低阶到高阶)是实现定义的。对齐方式 未指定可寻址存储单元。

这些“存储单元”仅由编译器在内部知道,并且在不同的编译器上可以有不同的大小。标准不支持位/字节“打包”的概念,并且不同编译器的行为也不同。

您的测试中使用的编译器都没有违反 C 标准,因为这是 100% 实现定义的行为。

【讨论】:

    【解决方案2】:

    打包请求编译器将成员打包到结构中,没有填充。但是,它们不会更改成员本身的类型或表示。似乎 GCC 和 Clang 使用三个字节来表示 17 位的位域,而 Microsoft 使用四个字节,至少在基本类型为 uint32_t 时。因此,对于这个结构,Clang 和 GCC 将一个 1 字节对象、一个 4 字节对象和一个 3 字节对象打包成 8 个字节,而 Microsoft 将一个 1 字节对象、一个 4 字节对象和一个 4 -byte 对象分成九个字节。

    这可能与微软的编译器主要是 C++ 编译器和C and C++ treat the types of bit-fields differently 的事实有关。在 C 中,位域的类型可能是实现定义的(标准并不完全清楚)。在 C++ 中,位域的类型是它的基类型。

    我们可以通过考虑重新排列解包结构来测试这一点:

    struct S
    {
        uint8_t  f0;
        uint32_t f2 : 17;
        uint32_t f1;
    };
    

    GCC 和 Clang 将 sizeof(struct S) 显示为 8 个字节,这与位字段的三字节表示一致。 MSVC 显示 12 个字节,这与位域的 4 字节表示是一致的。

    【讨论】:

      猜你喜欢
      • 2016-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-01
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 2011-02-08
      相关资源
      最近更新 更多