我正在使用32位机器,所以我认为内存对齐应该是4个字节。说我有结构:
typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
} myStruct;
实际大小是6个字节,我认为对齐的大小应该是8,但sizeof(myStruct)
会给我6个。
但是,如果我写:
typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
int i;
} myStruct;
实际大小为10个字节,对齐为12,此时为sizeof(myStruct) == 12
。
有人可以解释一下有什么区别吗?
答案 0 :(得分:49)
至少在大多数机器上,类型只能与类型本身一样大的边界对齐[编辑:你不能真正要求任何“更多”对齐,因为你必须能够创建数组,你不能将填充插入数组]。在您的实现中,short
显然是2个字节,int
4个字节。
这意味着您的第一个结构与2字节边界对齐。由于所有成员各占2个字节,因此不会在它们之间插入填充。
第二个包含一个4字节的项,它与4字节边界对齐。由于它前面有6个字节,因此在v3
和i
之间插入2个字节的填充,在short
s中提供6个字节的数据,填充两个字节,再增加4个字节int
中的数据总共为12个。
答案 1 :(得分:19)
忘记拥有不同的成员,即使你写了两个结构完全相同的结构,差异是它们声明的顺序不同,那么每个结构的大小可以(通常是)不同。
例如,请参阅此内容,
#include <iostream>
using namespace std;
struct A
{
char c;
char d;
int i;
};
struct B
{
char c;
int i; //note the order is different!
char d;
};
int main() {
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
}
将其编译为gcc-4.3.4
,您将获得此输出:
8
12
即使两个结构都有相同的成员,大小也不同!
Ideone的代码:http://ideone.com/HGGVl
最重要的是,标准没有讨论应该如何填充,因此编译器可以自由做出任何决定而你不能假设所有编译器做出同样的决定。
答案 2 :(得分:13)
默认情况下,值根据其大小对齐。因此,像short
这样的2字节值在2字节边界上对齐,像int
这样的4字节值在4字节边界上对齐
在您的示例中,在i
之前添加了2个字节的填充,以确保i
落在4字节边界上。
(整个结构在边界上对齐至少与结构中最大值一样大,因此您的结构将与4字节边界对齐。)
实际规则根据平台而有所不同 - Data structure alignment上的维基百科页面有更多详细信息。
编译器通常允许您通过(例如)#pragma pack
指令控制打包。
答案 3 :(得分:5)
假设:
sizeof(unsigned short) == 2
sizeof(int) == 4
然后我个人会使用以下内容(您的编译器可能会有所不同):
unsigned shorts are aligned to 2 byte boundaries
int will be aligned to 4 byte boundaries.
typedef struct
{
unsigned short v1; // 0 bytes offset
unsigned short v2; // 2 bytes offset
unsigned short v3; // 4 bytes offset
} myStruct; // End 6 bytes.
// No part is required to align tighter than 2 bytes.
// So whole structure can be 2 byte aligned.
typedef struct
{
unsigned short v1; // 0 bytes offset
unsigned short v2; // 2 bytes offset
unsigned short v3; // 4 bytes offset
/// Padding // 6-7 padding (so i is 4 byte aligned
int i; // 8 bytes offset
} myStruct; // End 12 bytes
// Whole structure needs to be 4 byte aligned.
// So that i is correctly aligned.
答案 4 :(得分:4)
首先,虽然填充的细节留给了编译器,但操作系统也对对齐要求施加了一些规则。这个答案假定您正在使用gcc,尽管操作系统可能会有所不同
要确定给定结构及其元素占用的空间,可以遵循以下规则:
首先,假设结构总是从一个正确对齐所有数据类型的地址开始。
然后对于结构中的每个条目:
sizeof(element)
给出的元素的原始大小。char[20]
数组的对齐要求与之相同
普通char
。最后,结构整体的对齐要求是每个元素的对齐要求的最大值。
gcc将在给定元素之后插入填充,以确保下一个(或者如果我们正在讨论最后一个元素的结构)正确对齐。它将永远重新排列结构中元素的顺序,即使这样可以节省内存。
现在对齐要求本身也有点奇怪。
0x0
,0x4
,0x8
或0xC
结尾。请注意,这也适用于大于4个字节的类型(例如double
和long double
)。double
只能放置在以0x0
或0x8
结尾的地址。唯一的例外是long double
仍然是4字节对齐,即使它实际上是12字节长。long double
是一个例外,必须是16字节对齐。答案 5 :(得分:2)
每种数据类型都需要在其自身大小的内存边界上对齐。因此short
需要在2字节边界上对齐,int
需要在4字节边界上。同样,long long
需要在8字节边界上。
答案 6 :(得分:2)
在第一个结构中,由于每个项的大小为short
,因此整个结构可以在short
边界上对齐,因此不需要在末尾添加任何填充。
在第二个结构中,int(可能是32位)需要进行字对齐,以便在v3
和i
之间插入填充以对齐i
。
答案 7 :(得分:1)
第二个sizeof(myStruct)
为12
的原因是在v3
和i
之间插入的填充,以便将i
对齐到32位边界。它有两个字节。
Wikipedia合理清楚地解释了填充和对齐。
答案 8 :(得分:0)
标准没有说明具有完整类型的结构的布局 - 它取决于编译器。它决定它需要int来开始边界才能访问它,但由于它必须对短路进行子边界内存寻址,所以不需要填充它们
答案 9 :(得分:0)
听起来它基于每个var的大小与bounderies对齐,因此地址是所访问大小的倍数(因此短路对齐到2,整数对齐到4等),如果你移动了其中一个在int之后的短路,sizeof(mystruct)
应该是10.当然这完全取决于正在使用的编译器以及它依次使用的设置。