结构元素的内存分配

时间:2014-06-12 10:46:43

标签: c memory structure allocation

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

例如,如果我有以下结构,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 / p

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

7 个答案:

答案 0 :(得分:4)

似乎在您的系统上,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!

请注意,大小,路线和填充取决于正在使用的目标系统和编译器。

答案 1 :(得分:0)

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

结构看起来像

0       8       16      24      32
AAAAaaaaBBBBBBBBCcccccccDDDDDDDDEEEEeeee

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

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

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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

这是依赖于编译器的行为。 有些编译器会在8位偏移后存储'double'。

如果你修改下面的结构,你会得到不同的结果。

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平台并且您将编译器设置设置为不填充结构元素[那么通过指针访问结构元素可能会生成'奇数'地址,处理器会生成异常。

答案 4 :(得分:0)

避免结构填充! #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

答案 5 :(得分:0)

每个结构也都有对齐要求

例如:

typedef struct structc_tag {     char c;``     双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个字节。即使在阵列中也能保证正确的对齐。你可以交叉检查

答案 6 :(得分:0)

  

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

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

很明显,您使用的编译器和体系结构要求double对齐八字节。这很明显,因为在char c之后有七个字节的填充。

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

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