C结构中的内存对齐

53 c c++ memory-alignment structure-packing

我正在使用32位机器,所以我认为内存对齐应该是4个字节.说我有结构:

typedef struct {
    unsigned short v1;
    unsigned short v2;
    unsigned short v3;
} myStruct;
Run Code Online (Sandbox Code Playgroud)

实际大小是6个字节,我想对齐大小应该是8,但sizeof(myStruct)返回6.

但是,如果我写:

typedef struct {
    unsigned short v1;
    unsigned short v2;
    unsigned short v3;
    int i;
} myStruct;
Run Code Online (Sandbox Code Playgroud)

实际大小是10个字节,对齐是12,这次sizeof(myStruct) == 12.

有人可以解释一下有什么区别吗?

Jer*_*fin 51

至少在大多数机器上,类型只能与类型本身一样大的边界对齐[编辑:你不能真正要求任何"更多"对齐,因为你必须能够创建数组,而你无法将填充插入数组].在您的实现上,short显然是2个字节,int4个字节.

这意味着您的第一个结构与2字节边界对齐.由于所有成员各占2个字节,因此不会在它们之间插入填充.

第二个包含一个4字节的项,它与4字节边界对齐.由于它之前是6个字节,因此在v3和之间插入2个字节的填充i,在shorts中给出6个字节的数据,在两个字节的填充中,以及int总共12 个字节中的4个字节的数据.

  • @Ivan技术上它与结构中任何项目的最大*alignment*对齐(这与你所说的略有不同). (14认同)
  • @VitalikVerhovodov:数组之间不能有填充,因此N个项目的数组总是大小恰好是单个项目大小的N*. (2认同)

Naw*_*waz 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;
}
Run Code Online (Sandbox Code Playgroud)

用它编译gcc-4.3.4,你得到这个输出:

8
12
Run Code Online (Sandbox Code Playgroud)

也就是说,即使两个结构具有相同的成员,大小也是不同的!

Ideone的代码:http://ideone.com/HGGVl

底线是标准没有讨论如何填充,因此编译器可以自由做出任何决定,你不能假设所有编译器做出同样的决定.

  • 嗯,这是分裂的头发吗?使用gcc4.3.4的事件,你可以在另一个平台上获得不同的结果(我们在很久以前在TI DSP上使用了gcc,其中sizeof(char)== sizeof(int)和CHAR_BIT == 16.当然,*有*你可以用int和long玩过同样的游戏...). (2认同)

Ric*_*dle 13

默认情况下,值根据其大小对齐.因此,像a这样的2字节值short在2字节边界上对齐,而像a这样的4字节值int在4字节边界上对齐

在您的示例中,之前添加了2个字节的填充,i以确保i落在4字节边界上.

(整个结构的边界至少一样大,在结构上最大的价值取向上,所以你的结构将被对齐到4字节边界.)

实际规则根据平台而有所不同 - 维基百科有关数据结构对齐的页面有更多详细信息.

编译器通常允许您通过(例如)#pragma pack指令控制打包.


Abh*_*uch 5

首先,虽然填充的细节留给了编译器,但操作系统还对对齐要求强加了一些规则。该答案假设您使用的是gcc,尽管操作系统可能会有所不同

要确定给定结构及其元素所占用的空间,可以遵循以下规则:

首先,假设该结构始终从针对所有数据类型正确对齐的地址开始。

然后对于结构中的每个条目:

  • 所需的最小空间是给出的元素的原始大小sizeof(element)
  • 元素的对齐要求是元素基本类型的对齐要求。值得注意的是,这意味着char[20]数组的对齐要求与plain的要求相同char

最后,结构整体的对齐要求是其每个元素的对齐要求的最大值。

gcc将在给定元素之后插入填充,以确保下一个(如果我们在谈论最后一个元素,则为struct)正确对齐。即使将节省内存,它也不会重新排列结构中元素的顺序。

现在对齐要求本身也有些奇怪。

  • 32位Linux要求2字节数据类型必须2字节对齐(其地址必须为偶数)。所有更大的数据类型必须具有4字节对齐(地址结束在0x00x40x80xC)。请注意,这也适用于大于4个字节的类型(例如doublelong double)。
  • 32位Windows更为严格,因为如果类型的大小为K字节,则必须将其对齐为K字节。这意味着a double只能放在以0x0或结尾的地址中0x8。唯一的例外是,long double尽管它实际上是12字节长,但仍然对齐4字节。
  • 对于Linux和Windows,在64位计算机上,K字节类型必须对齐K字节。同样,long double是一个例外,必须对齐16字节。


Mar*_*ork 5

假设:

sizeof(unsigned short) == 2
sizeof(int)            == 4
Run Code Online (Sandbox Code Playgroud)

然后我个人会使用以下(您的编译器可能会有所不同):

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.
Run Code Online (Sandbox Code Playgroud)