结构元素的内存分配

嗨,我很难理解如何将内存分配给结构元素。

例如,如果我具有以下结构并且char的大小是1并且int分别是4个字节。

struct temp { char a; int b; }; 

我知道结构的大小是8.因为在char之后将有3个字节的填充,并且下一个元素应该以4的倍数放置,因此大小将为8。

现在考虑以下结构。

 struct temp { int a; // size is 4 double b; // size is 8 char c; // size is 4 double d; // size is 8 int e; // size is 4 }; 

这是上述结构的o / pi

 size of node is 40 the address of node is 3392515152 ( =: base) the address of a in node is 3392515152 (base + 0) the address of b in node is 3392515160 (base + 8) the address of c in node is 3392515168 (base + 16) the address of d in node is 3392515176 (base + 24) the address of e in node is 3392515184 (base + 32) 

总内存总和最多36个字节,为什么它显示为40个字节? 如果我们创建一个这样的结构的数组也可以将下一个数组元素的第一个元素放在3392515188(base + 36)中,因为它是4的倍数,但为什么不以这种方式发生呢?

任何人都可以解决我的疑问。

谢谢,Saravana

似乎在你的系统上, double必须具有8的对齐。

 struct temp { int a; // size is 4 // padding 4 bytes double b; // size is 8 char c; // size is 1 // padding 7 bytes double d; // size is 8 int e; // size is 4 // padding 4 bytes }; // Total 4+4+8+1+7+8+4+4 = 40 bytes 

编译器在结构的末尾添加额外的4个字节,以确保array[1].b将正确对齐。

没有结束填充(假设数组在地址0):

 &array[0] == 0 &array[1] == 36 &array[1].b == 36 + 8 == 44 44 % 8 == 4 -> ERROR, not aligned! 

使用结束填充(假设数组位于地址0):

 &array[0] == 0 &array[1] == 40 &array[1].b == 40 + 8 == 48 48 % 8 == 0 -> OK! 

请注意,大小,对齐和填充取决于使用的目标系统和编译器。

在您的计算中,您忽略了e也需要填充的事实:

结构看起来像

 0 8 16 24 32 AAAAaaaaBBBBBBBBCcccccccDDDDDDDDEEEEeeee 

其中大写是变量本身,小写是应用于它的填充。

如您所见(以及地址),每个字段填充为8个字节,这是结构中最大的字段。

由于结构可能在数组中使用,并且所有数组元素也应该良好对齐,因此填充e是必要的。

严重依赖于处理器架构和编译器。 现代机器和编译器可以选择更大或更小的填充来降低数据的访问成本。

四字节对齐意味着两个地址线未使用。 八,三。 芯片可以使用它来使用相同数量的硬件来处理更多内存(更粗糙的颗粒)。

由于各种原因,编译器可能会使用类似的技巧,但是不需要编译器来执行任何操作,只需要处理器的细粒度。 通常,他们只会采用最大尺寸的值并专门用于该块。 在你的情况下,这是一个double ,即八个字节。

这是依赖于编译器的行为。 一些编译器使得在8位偏移之后存储“双”。

如果您修改如下结构,您将得到不同的结果。

 struct temp { double b; // size is 8 int a; // size is 4 int e; // size is 4 double d; // size is 8 char c; // size is 4 } 

每个程序员都应该知道编译器正在做什么填充。 例如,如果您正在使用ARM平台并且您将编译器设置设置为不填充结构元素[则通过指针访问结构元素可能会生成“奇数”地址,处理器会生成exception。

每个结构也都有对齐要求

例如 :

typedef struct structc_tag {char c;“double d; int s; } structc_t;

应用相同的分析,structc_t需要sizeof(char)+ 7字节填充+ sizeof(double)+ sizeof(int)= 1 + 7 + 8 + 4 = 20字节。 但是,sizeof(structc_t)将是24个字节。 这是因为,与结构成员一起,结构类型变量也将具有自然对齐。 让我们通过一个例子来理解它。 比如说,我们声明了一个structc_t数组,如下所示structc_t structc_array [3];

假设,structc_array的基址是0×0000,便于计算。 如果structc_t在我们计算时占用20(0×14)个字节,则第二个structc_t数组元素(索引为1)将为0×0000 + 0×0014 = 0×0014。 它是数组索引1元素的起始地址。 该structc_t的double成员将被分配在0×0014 + 0×1 + 0×7 = 0x001C(十进制28),这不是8的倍数,并且与double的对齐要求相冲突。 正如我们在顶部提到的,double的对齐要求是8个字节。 为了避免这种错位,编译器将为每个结构引入对齐要求。 它将是该结构中最大的成员。 在我们的例子中,structa_t的对齐是2,structb_t是4,structc_t是8.如果我们需要嵌套结构,最大内部结构的大小将是直接更大结构的对齐。

在上面程序的structc_t中,在int成员之后将有4个字节的填充,以使结构大小为其对齐的倍数。 因此sizeof(structc_t)是24个字节。 即使在数组中也能保证正确的对齐。 你可以交叉检查

避免结构填充! #pragma pack ( 1 )指令可用于为结构成员安排内存,紧邻其他结构成员的末尾。

 #pragma pack(1) struct temp { int a; // size is 4 int b; // size is 4 double s; // size is 8 char ch; //size is 1 }; 

结构的大小是:17

如果我们创建一个这样的结构的数组也可以将下一个数组元素的第一个元素放在3392515188(base + 36)中,因为它是4的倍数,但为什么不以这种方式发生呢?

它不能因为那里的double元素。

很明显,您使用的编译器和体系结构需要一个double八进制八字节。 这是显而易见的,因为在char c之后有七个字节的填充。

此要求还意味着整个结构必须是八字节对齐的。 如果struct本身只有四个字节对齐,那么仔细地将所有double s对齐到相对于struct的开头的八个字节是毫无意义的。 因此,在最终的int之后填充以使sizeof(temp)成为8的倍数。

请注意,这种对齐要求不一定是硬性要求。 编译器可以选择进行对齐,即使double s可以是四字节对齐,理由是如果只有四个字节对齐,可能需要更多的存储器周期来访问double