为什么sizeof运算符返回的结构大小大于结构成员的总大小?


当前回答

C语言为编译器提供了一些关于内存中结构元素位置的自由:

内存孔可能出现在任意两个组件之间以及最后一个组件之后。这是由于目标计算机上的某些类型的对象可能受到寻址边界的限制sizeof运算符的结果中包含“内存孔”大小。sizeof仅不包括灵活数组的大小,灵活数组在C/C中可用++该语言的一些实现允许您通过pragma和编译器选项控制结构的内存布局

C语言为程序员提供了结构中元素布局的一些保证:

编译器需要分配一系列增加内存地址的组件第一个组件的地址与结构的起始地址一致未命名的位字段可以包括在结构中,以实现相邻元素的所需地址对齐

与元素对齐相关的问题:

不同的计算机以不同的方式排列对象的边缘位字段宽度的不同限制计算机在如何存储一个字中的字节方面存在差异(Intel 80x86和Motorola 68000)

对齐方式:

结构所占据的体积被计算为这样的结构阵列中对齐的单个元素的大小。结构应以便下一个后续结构的第一个元素不违反对齐要求

p.s更多详细信息可在此处获得:“塞缪尔·p·哈比森,盖伊·L·斯蒂尔C A参考,(5.6.2-5.6.7)”

其他回答

另请参见:

对于Microsoft Visual C:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

GCC声称与微软编译器兼容

https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Structure_002dPacking-Pragmas.html

除了前面的答案,请注意,无论包装如何,C++中没有成员订单保证。编译器可以(当然也可以)向结构中添加虚拟表指针和基结构的成员。即使是虚拟表的存在也没有得到标准的保证(没有规定虚拟机制的实现),因此可以得出这样的保证是不可能的。

我很确定C语言保证了成员顺序,但在编写跨平台或跨编译器程序时,我不会指望它。

上面给出了很多信息(解释)。

我只想分享一些方法来解决这个问题。

您可以通过添加pragma pack来避免它

#pragma pack(push, 1)

// your structure

#pragma pack(pop) 

例如,如果您希望结构具有GCC的特定大小,请使用__attribute__((打包))。

在Windows上,使用带有/Zp选项的cl.exe编译器时,可以将对齐设置为一个字节。

通常,CPU更容易访问4(或8)的倍数的数据,这取决于平台和编译器。

所以这基本上是一个对齐问题。

你需要有充分的理由来改变它。

C语言为编译器提供了一些关于内存中结构元素位置的自由:

内存孔可能出现在任意两个组件之间以及最后一个组件之后。这是由于目标计算机上的某些类型的对象可能受到寻址边界的限制sizeof运算符的结果中包含“内存孔”大小。sizeof仅不包括灵活数组的大小,灵活数组在C/C中可用++该语言的一些实现允许您通过pragma和编译器选项控制结构的内存布局

C语言为程序员提供了结构中元素布局的一些保证:

编译器需要分配一系列增加内存地址的组件第一个组件的地址与结构的起始地址一致未命名的位字段可以包括在结构中,以实现相邻元素的所需地址对齐

与元素对齐相关的问题:

不同的计算机以不同的方式排列对象的边缘位字段宽度的不同限制计算机在如何存储一个字中的字节方面存在差异(Intel 80x86和Motorola 68000)

对齐方式:

结构所占据的体积被计算为这样的结构阵列中对齐的单个元素的大小。结构应以便下一个后续结构的第一个元素不违反对齐要求

p.s更多详细信息可在此处获得:“塞缪尔·p·哈比森,盖伊·L·斯蒂尔C A参考,(5.6.2-5.6.7)”

打包和字节对齐,如C常见问题解答中所述:

这是为了对齐。许多处理器无法访问2字节和4字节数量(例如整数和长整数),如果它们被塞进每个方向。假设您有这样的结构:结构{字符a[3];短整数b;长整型c;字符d[3];};现在,你可能认为应该可以打包这个结构如下:+-------+-------+-------+-------+|a | b|+-------+-------+-------+-------+|b | c|+-------+-------+-------+-------+|c | d(c | d)|+-------+-------+-------+-------+但如果编译器安排,则处理器上的操作要简单得多它是这样的:+-------+-------+-------+|一个|+-------+-------+-------+|b级|+-------+-------+-------+-------+|c类|+-------+-------+-------+-------+|d)|+-------+-------+-------+在打包版本中,请注意,对于你和我想看看b和c字段是如何换行的?简而言之处理器也很难。因此,大多数编译器都会填充结构(好像有额外的、不可见的字段)如下:+-------+-------+-------+-------+|a |焊盘1|+-------+-------+-------+-------+|b |焊盘2|+-------+-------+-------+-------+|c类|+-------+-------+-------+-------+|d|焊盘3|+-------+-------+-------+-------+