C 结构中的内存对齐
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5435841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Memory alignment in C-structs
提问by
I'm working on the 32-bit machine, so I suppose that memory alignment should be 4 bytes. Say I have struct:
我在 32 位机器上工作,所以我想内存对齐应该是 4 个字节。说我有结构:
typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
} myStruct;
the real size is 6 bytes, and I suppose that aligned size should be 8, but sizeof(myStruct)
returns me 6.
实际大小是 6 个字节,我想对齐的大小应该是 8,但sizeof(myStruct)
返回我 6。
However if I write:
但是,如果我写:
typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
int i;
} myStruct;
the real size is 10 bytes, aligned is 12, and this time sizeof(myStruct) == 12
.
实际大小是 10 字节,对齐是 12,而这次sizeof(myStruct) == 12
.
Can somebody explain what is the difference?
有人可以解释一下有什么区别吗?
采纳答案by Jerry Coffin
At least on most machines, a type is only ever aligned to a boundary as large as the type itself [Edit: you can't really demand any "more" alignment than that, because you have to be able to create arrays, and you can't insert padding into an array]. On your implementation, short
is apparently 2 bytes, and int
4 bytes.
至少在大多数机器上,一个类型只与类型本身一样大的边界对齐[编辑:你真的不能要求任何“更多”对齐,因为你必须能够创建数组,并且你无法将填充插入数组]。在您的实现中,short
显然是 2 个字节和int
4 个字节。
That means your first struct is aligned to a 2-byte boundary. Since all the members are 2 bytes apiece, no padding is inserted between them.
这意味着您的第一个结构与 2 字节边界对齐。由于所有成员都是 2 个字节,因此它们之间没有插入填充。
The second contains a 4-byte item, which gets aligned to a 4-byte boundary. Since it's preceded by 6 bytes, 2 bytes of padding is inserted between v3
and i
, giving 6 bytes of data in the short
s, two bytes of padding, and 4 more bytes of data in the int
for a total of 12.
第二个包含一个 4 字节的项目,它与 4 字节的边界对齐。由于它前面是 6 个字节,因此在v3
和之间插入了 2 个字节的填充i
,从而在short
s 中给出了 6 个字节的数据,在s 中给出了两个字节的填充,以及在int
12中的另外 4 个字节的数据。
回答by Nawaz
Forget about having different members, even if you write two structs whose members are exactlysame, with a differenceis that the order in which they're declared is different, then size of each struct can be (and often is) different.
忘掉具有不同的成员,即使你写两个结构,其成员都是完全相同一样,有一个区别是,在他们声明的顺序是不同的,那么每个结构的大小可以(而且经常是)不同的。
For example, see this,
例如,看到这个,
#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;
}
Compile it with gcc-4.3.4
, and you get this output:
用 编译它gcc-4.3.4
,你会得到这个输出:
8
12
That is, sizes are different even though both structs has same members!
也就是说,即使两个结构具有相同的成员,大小也是不同的!
Code at Ideone : http://ideone.com/HGGVl
Ideone 代码:http://ideone.com/HGGVl
The bottomline is that the Standard doesn't talk about how padding should be done, and so the compilers are free to make any decision and you cannotassume all compilers make the same decision.
底线是标准没有讨论应该如何进行填充,因此编译器可以自由做出任何决定,您不能假设所有编译器都做出相同的决定。
回答by RichieHindle
By default, values are aligned according to their size. So a 2-byte value like a short
is aligned on a 2-byte boundary, and a 4-byte value like an int
is aligned on a 4-byte boundary
默认情况下,值根据其大小对齐。所以像 a 这样的 2 字节值short
在 2 字节边界上对齐,而像 an 这样的 4 字节值int
在 4 字节边界上对齐
In your example, 2 bytes of padding are added before i
to ensure that i
falls on a 4-byte boundary.
在您的示例中,之前添加了 2 个字节的填充i
以确保i
落在 4 个字节的边界上。
(The entire structure is aligned on a boundary at least as big as the biggest value in the structure, so your structure will be aligned to a 4-byte boundary.)
(整个结构在至少与结构中最大值一样大的边界上对齐,因此您的结构将与 4 字节边界对齐。)
The actual rules vary according to the platform - the Wikipedia page on Data structure alignmenthas more details.
实际规则因平台而异 - 关于数据结构对齐的维基百科页面有更多详细信息。
Compilers typically let you control the packing via (for example) #pragma pack
directives.
编译器通常让您通过(例如)#pragma pack
指令控制打包。
回答by Abhay Buch
Firstly, while the specifics of padding are left up to the compiler, the OS also imposes some rules as to alignment requirements. This answer assumes that you are using gcc, though the OS may vary
首先,虽然填充的细节由编译器决定,但操作系统也强加了一些关于对齐要求的规则。此答案假定您使用的是 gcc,但操作系统可能会有所不同
To determine the space occupied by a given struct and its elements, you can follow these rules:
要确定给定结构及其元素占用的空间,您可以遵循以下规则:
First, assume that the struct always starts at an address that is properly aligned for alldata types.
首先,假设该结构始终从所有数据类型正确对齐的地址开始。
Then for every entry in the struct:
然后对于结构中的每个条目:
- The minimum space needed is the raw size of the element given by
sizeof(element)
. - The alignment requirement of the element is the alignment requirement of the element's base type.
Notably, this means that the alignment requirement for a
char[20]
array is the same as the requirement for a plainchar
.
- 所需的最小空间是由 给出的元素的原始大小
sizeof(element)
。 - 元素的对齐要求是元素基类型的对齐要求。值得注意的是,这意味着
char[20]
数组的对齐要求与普通char
.
Finally, the alignment requirement of the struct as a whole is the maximum of the alignment requirements of each of its elements.
最后,整个结构体的对齐要求是其每个元素的对齐要求的最大值。
gcc will insert padding after a given element to ensure that the next one (or the struct if we are talking about the last element) is correctly aligned. It will neverrearrange the order of the elements in the struct, even if that will save memory.
gcc 将在给定元素之后插入填充以确保下一个元素(或结构,如果我们谈论的是最后一个元素)正确对齐。它永远不会重新排列结构中元素的顺序,即使这会节省内存。
Now the alignment requirements themselves are also a bit odd.
现在对齐要求本身也有点奇怪。
- 32-bit Linux requires that 2-byte data types have 2-byte alignment (their addresses must be even). All larger data types must have 4-byte alignment (addresses ending in
0x0
,0x4
,0x8
or0xC
). Note that this applies to types larger than 4 bytes as well (such asdouble
andlong double
). - 32-bit Windows is more strict in that if a type is K bytes in size, it must be K byte aligned. This means that a
double
can only placed at an address ending in0x0
or0x8
. The only exception to this is thelong double
which is still 4-byte aligned even though it is actually 12-bytes long. - For both Linux and Windows, on 64-bit machines, a K byte type must be K byte aligned. Again, the
long double
is an exception and must be 16-byte aligned.
- 32 位 Linux 要求 2 字节数据类型具有 2 字节对齐(它们的地址必须是偶数)。所有更大的数据类型必须具有4字节对齐(地址结束在
0x0
,0x4
,0x8
或0xC
)。请注意,这也适用于大于 4 个字节的类型(例如double
和long double
)。 - 32 位 Windows 更严格,因为如果类型的大小为 K 字节,则它必须是 K 字节对齐的。这意味着 a
double
只能放在以0x0
或结尾的地址上0x8
。唯一的例外是long double
它仍然是 4 字节对齐的,即使它实际上是 12 字节长。 - 对于 Linux 和 Windows,在 64 位机器上,K 字节类型必须是 K 字节对齐的。同样,这
long double
是一个例外,必须是 16 字节对齐的。
回答by Martin York
Assuming:
假设:
sizeof(unsigned short) == 2
sizeof(int) == 4
Then I personally would use the following (your compiler may differ):
然后我个人会使用以下内容(您的编译器可能会有所不同):
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.
回答by Mark B
In your first struct, since every item is of size short
, the whole struct can be aligned on short
boundaries, so it doesn't need to add any padding at the end.
在您的第一个结构中,由于每个项目都是 size short
,因此整个结构可以在short
边界上对齐,因此不需要在末尾添加任何填充。
In the second struct, the int (presumably 32 bits) needs to be word aligned so it inserts padding between v3
and i
to align i
.
在第二个结构中, int (大概是 32 位)需要字对齐,因此它在v3
和之间插入填充i
以 align i
。
回答by Jonathan
Each data type needs to be aligned on a memory boundary of its own size. So a short
needs to be on aligned on a 2-byte boundary, and an int
needs to be on a 4-byte boundary. Similarly, a long long
would need to be on an 8-byte boundary.
每种数据类型都需要在其自身大小的内存边界上对齐。所以 ashort
需要在 2 字节边界上对齐,anint
需要在 4 字节边界上对齐。同样, along long
需要在 8 字节的边界上。
回答by NPE
回答by Martin Beckett
The standard doesn't say much about the layout of structs with complete types - it's upto to the compiler. It decided that it needs the int to start on a boundary to access it, but since it has to do sub-boundary memory addressing for the shorts there is no need to pad them
该标准并没有说明具有完整类型的结构的布局 - 这取决于编译器。它决定需要 int 从边界开始访问它,但由于它必须为短裤做子边界内存寻址,因此不需要填充它们
回答by Necrolis
Sounds like its being aligned to bounderies based on the size of each var, so that the address is a multiple of the size being accessed(so shorts are aligned to 2, ints aligned to 4 etc), if you moved one of the shorts after the int, sizeof(mystruct)
should be 10. Of course this all depends on the compiler being used and what settings its using in turn.
听起来它根据每个 var 的大小与边界对齐,因此地址是所访问大小的倍数(因此短裤对齐为 2,整数对齐为 4 等),如果您在之后移动了一个短裤int,sizeof(mystruct)
应该是 10。当然,这一切都取决于所使用的编译器以及它依次使用的设置。