学科分类
目录
C语言

结构体变量的存储方式

结构体变量一旦被定义,系统就会为其分配内存。为方便系统对变量的访问,保证读取性能,结构体变量中各成员在内存中的存储遵循字节对齐机制,该机制的具体规则如下:

(1)结构体变量的首地址能够被其最宽基本类型成员的大小整除。

(2)结构体每个成员相对于结构体首地址的偏移量都是该成员大小的整数倍,且能够被最宽基本类型成员的大小整除。如有需要,编译器会在成员之间加上填充字节。

(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员后面加上填充字节。

假设定义一个结构体类型struct Note,并定义相应变量nt,示例代码如下:

struct Note
{
  char a;
  double b;
  int c;
  short d;
};

struct Note nt; //定义struct Note结构体变量

在上述代码中,按基础数据类型计算,char、double、int、short四种数据类型共占据15个字节。但作为结构体变量计算,拥有这四项成员的结构体变量共占据24个字节。

在struct Note变量nt中,double类型变量b占据最多字节,是最宽基本类型成员,编译器以double类型的长度8字节为准,按字节对齐机制为各成员变量分配内存。首先,编译器会寻找内存地址能被double数据类型大小(8字节)整除的位置,作为结构体的首地址。接着编译器为每个成员变量分配内存空间,在为每个成员变量分配内存空间时,编译器会计算预分配内存空间的首地址相对于结构体首地址的偏移量是否是本成员的整数倍,且能够被8(sizeof(double))整除,若满足要求,就为成员分配内存空间,否则就在本成员和上一个成员之间填充一定数量的字节。最后,编译器会计算所有成员所占内存空间大小(包括填充字节)是否是8(sizeof(double))的整数倍,若是,则完成内存空间分配,否则,在最后一个成员后面填充一定数量字节。struct Note结构体类型变量nt的各成员内存分配情况如图1所示。

图1 struct Note类型变量nt各成员内存分配

在图1中,灰色区域是填充字节,变量nt中各成员的填充情况为:变量a占据1个字节,填充7个字节;变量d占据2个字节,末尾填充2个字节。

下面通过输出struct Note类型变量nt的地址及各成员的地址,以验证其内存分配情况,如例1所示。

例1 note.c

 1  #include <stdio.h>
 2  struct Note                          //定义结构体类型
 3  {
 4    char a;
 5    double b;
 6    int c;
 7    short d;
 8  };
 9  int main()
 10  {
 11    struct Note nt;                  //定义struct Note结构体变量
 12    printf("&nt=%p\n", &nt);         //输出结构体首地址
 13    printf("&a=%p\n", &nt.a);         //输出成员变量a的地址
 14    printf("&b=%p\n", &nt.b);         //输出成员变量b的地址
 15    printf("&c=%p\n", &nt.c);         //输出成员变量c的地址
 16    printf("&d=%p\n", &nt.d);         //输出成员变量d的地址
 17    printf("size:%d\n", sizeof(nt)); //计算结构体变量nt的大小
 18   return 0;
 19  }

例1运行结果如图2所示。

图2 例1运行结果

下面结合图9-3分析结构体变量nt及其各成员的内存分配情况,具体如下:

(1)结构体变量nt的首地址为002EFBDC,可以被8(sizeof(double))整除。

(2)成员变量a的地址与结构体变量首地址是同一个地址。

(3)成员变量b的地址为002EFBE4,它与成员变量a的地址相差8字节,由于成员变量a为char类型,占1字节内存,因此成员变量b与成员变量a之间有7个字节的填充区域。

(4)成员变量c的地址为002EFBEC,它与成员变量b的地址相差8字节,这正好是成员变量b的大小,表明成员变量b与成员变量c之间没有填充字节。

(5)成员变量d的地址为002EFBF0,它与成员变量c之间相差4字节,这正好是成员变量c的大小,表明成员变量c与成员变量d之间也没有填充字节。

(6)成员变量d的地址与结构体变量首地址相差20字节,由于成员变量d为short类型,占据2字节内存,如此计算,结构体变量nt各成员所占内存大小为22字节(20+2)。由于22不能被8(sizeof(double))整除,因此编译器在成员变量d后面填充了2个字节,结构体变量nt占内存总大小为24字节。

点击此处
隐藏目录