结构填充信息

时间:2013-04-14 10:45:17

标签: c struct padding unions bit-fields

struct abc
{
  char arr[7];
  char arr1[2];
  int i:24;
};

在上面使用sizeof运算符的结构中,我的大小为12字节。但根据我的计算(可能是错误的)它应该是16字节。为什么它给12个字节?

另一个问题:

根据C99第6.7.2.1节第14段

  

结构或联合对象的每个非位字段成员都对齐   一种适合其类型的实现定义方式。

对于特定的实现,我将在哪里获得描述特定编译器(例如gcc)如何在结构中引入填充的文档?对于特定架构的所有编译器是否有任何通用规则?

2 个答案:

答案 0 :(得分:2)

结构布局是实现定义的。事实证明,GCC使用的默认布局与MSVC使用的布局不同。我猜你已经习惯了MSVC布局包含位域的结构。

当然,GCC属性ms_struct允许您更改行为。这在documentation

中有更详细的描述

所以,这个结构的大小为16:

struct abc
{
  char arr[7];
  char arr1[2];
  int i:24;
} __attribute__((ms_struct));

如果使用默认的gcc_struct选项,则大小为12。

  

对于特定的实现,我将在哪里获得描述特定编译器(例如GCC)如何在结构中引入填充的文档?

您需要查阅每个编译器的文档。对于GCC,documentation says

  

4.9结构,联合,枚举和位字段

     
      
  • 使用不同类型的成员(C90 6.3.2.3)访问union对象的成员。

      对象的表示被视为所用类型的对象   用于访问。请参阅类型惩罚。这可能是陷阱表示。

  •   
  • “plain”int位字段是作为signed int位字段还是作为unsigned int位字段处理(C90 6.5.2,C90 6.5.2.1,C99)   6.7.2,C99 6.7.2.1)。

    在默认情况下,它被视为符号int,但可以通过-funsigned-bitfields选项进行更改。

  •   
  • _Bool,signed int和unsigned int以外的允许位字段类型(C99 6.7.2.1)。

    其他类型不允许使用   严格遵守模式。

  •   
  • 位域是否可以跨越存储单元边界(C90 6.5.2.1,C99 6.7.2.1)。

    由ABI决定。

  •   
  • 单位内位域分配的顺序(C90 6.5.2.1,C99 6.7.2.1)。

    由ABI确定。

  •   
  • 结构的非位域成员的对齐(C90 6.5.2.1,C99 6.7.2.1)。
    由ABI确定。

  •   
  • 与每个枚举类型兼容的整数类型(C90 6.5.2.2,C99 6.7.2.2)。

    通常,如果有,则类型为unsigned int   枚举中没有负值,否则为int。如果-fshort-enums   指定,如果有负值则是第一个   signed char,short和int,可以表示所有值,   否则它是unsigned char中的第一个,unsigned short和   unsigned int,可以代表所有的值。

    在某些方面   目标,-shshort-enums是默认值;这由ABI确定。

  •   

因此,总的来说,您需要弄清楚您的平台的ABI是什么。对于任何编译器来说,这都是理智的事情。如果它没有根据ABI布局结构,那么它会使互操作非常棘手。

有点奇怪的是,GCC对于Windows上ABI的看法与MSVC实现不同。我不知道为什么会这样。

答案 1 :(得分:1)

这很简单。

struct abc
{
  char arr[7];  // occupies 7 bytes
  char arr1[2]; // occupies 2 bytes
  int i:24;     // occupies 3 bytes
};

现在,在第3个声明(i)中,只需要3个字节。你已经拥有如下:

0 1 2 3 // All 4 bytes used for `char arr[7]`
0 1 2 3 // 3 more used for `char arr[7]`, 1 used for `char arr1[2]`
0 1 2 3 // 1 used for `char arr1[2]`, and the remaining 3 bytes will be used for `int i:24`

但是如果你使用int i(没有位域),它将消耗16个字节,因为

0 1 2 3 // All 4 bytes used for `char arr[7]`
0 1 2 3 // 3 more used for `char arr[7]`, 1 used for `char arr1[2]`
0 1 2 3 // 1 used for `char arr1[2]`, there are still 3 bytes but we need 4 bytes for an `int`
0 1 2 3 // So the compiler will allocate a new 4 byte chunk for `int i`

我认为现在很清楚。