C 结构元素的内存分配

C 结构元素的内存分配,c,memory,structure,allocation,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; //

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

例如,如果我有下面的结构,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

在您的系统上,
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个字节,以确保
数组[1].b
正确对齐

无结尾填充(假设数组位于地址0):

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


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

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

结构看起来像

0       8       16      24      32
AAAAaaaaBBBBBBBBCcccccccDDDDDDDDEEEEeeee
其中大写是变量本身,小写是应用于它的填充

正如您所看到的(以及从地址中看到的),每个字段填充为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
};
由于该结构可能在数组中使用,并且所有数组元素也应该很好地对齐,因此有必要对
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平台上工作,并且将编译器设置为不填充结构元素[然后通过指针访问结构元素可能会生成“奇数”地址,处理器会为该地址生成异常。

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

每个结构也有对齐要求

例如:

typedef struct struct_标记 { 字符c`` 双d; int-s; }结构

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

假设structc_数组的基址为0×0000以便于计算。如果structc_t在我们计算时占用20(0×14)字节,则第二个structc_t数组元素(索引为1)将位于0×0000+0×0014=0×0014。它是数组索引1元素的起始地址。此结构的双成员将分配到0×0014+0×1+0×7=0x001C(十进制28)它不是8的倍数,并且与double的对齐要求冲突。正如我们在顶部提到的,double的对齐要求是8字节。为了避免这种不对齐,编译器将向每个结构引入对齐要求。它将作为结构中最大成员的对齐要求。在我们的例子中structa_t是2,structb_t是4,structc_t是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
};
在上述程序的structc_t中,int member之后将有4个字节的填充,以使结构大小成为其对齐的倍数。因此,sizeof(structc_t)是24个字节。它保证即使在数组中也能正确对齐。您可以交叉检查

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

因为里面有
double
元素,所以不能使用

很明显,您正在使用的编译器和体系结构要求将
double
与8个字节对齐。这很明显,因为
char c
后面有7个字节的填充

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

请注意,此对齐要求不一定是硬要求。编译器可以选择进行对齐,即使
double
s可以是四字节对齐,因为可能需要