【问题标题】:Packed bit fields in c structures - GCCc结构中的打包位字段 - GCC
【发布时间】:2025-12-01 23:35:01
【问题描述】:

我在 linux 上使用 c 中的结构。 我开始使用位字段和“打包”属性,但遇到了一个奇怪的行为:

struct __attribute__((packed)) {
    int a:12;
    int b:32;
    int c:4;
} t1;

struct __attribute__((packed))  {
    int a:12;
    int b;
    int c:4;
}t2;

void main()
{
    printf("%d\n",sizeof(t1)); //output - 6
    printf("%d\n",sizeof(t2)); //output - 7
}

为什么这两种结构 - 完全相同 - 占用不同的字节数?

【问题讨论】:

标签: c gcc struct bit-fields packed


【解决方案1】:
struct t1 // 6 bytes
{
    int a:12; // 0:11
    int b:32; // 12:43
    int c:4;  // 44:47
}__attribute__((packed));

struct t1 // 7 bytes
{
    int a:12; // 0:11
    int b;    // 16:47
    int c:4;  // 48:51
}__attribute__((packed));

常规的int b 必须与字节边界对齐。所以在它之前有填充。如果您将c 放在a 旁边,则不再需要此填充。您应该这样做,因为访问像 int b:32 这样的非字节对齐整数很慢。

【讨论】:

  • as accessing non-byte-aligned integers like int b:32 is slow 来源?定义慢。它不只是转移和掩盖内存值吗?
  • 视情况而定,但它永远不会像字节对齐那样快。多慢(甚至我们如何定义慢)取决于应用程序、编译器等。
  • 明白了,我猜这只是快速移位+掩码的问题。
【解决方案2】:

您的结构并不“完全相同”。你的第一个有三个连续的位域,第二个有一个位域,一个(非位域)int,然后是第二个位域。

这很重要:连续(非零宽度)位域被合并到一个内存位置,而一个位域后跟一个非位域是不同的内存位置。

你的第一个结构只有一个内存位置,你的第二个有三个。您可以在第二个结构中获取b 成员的地址,而不是在您的第一个结构中。对b 成员的访问不会与您的第二个结构中的ac 的访问竞争,但它们会在您的第一个结构中进行。

在某种意义上,在位域成员“关闭”它之后立即拥有一个非位域(或零长度位域),接下来将是一个不同/独立的内存位置/对象。编译器无法像在第一个结构中那样将b 成员“打包”在位域中。

【讨论】: