struct abc
{
char arr[7];
char arr1[2];
int i:24;
};
在上面使用sizeof运算符的结构中,我的大小为12字节。但根据我的计算(可能是错误的)它应该是16字节。为什么它给12个字节?
另一个问题:
根据C99第6.7.2.1节第14段
结构或联合对象的每个非位字段成员都对齐 一种适合其类型的实现定义方式。
对于特定的实现,我将在哪里获得描述特定编译器(例如gcc)如何在结构中引入填充的文档?对于特定架构的所有编译器是否有任何通用规则?
答案 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`
我认为现在很清楚。