23

我正在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
}

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

4

2 回答 2

39

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

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

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

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

于 2014-09-13T11:41:39.023 回答
25
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的速度很慢。

于 2014-09-13T11:41:20.177 回答