我们使用的电子计算机绝大部分都是冯·诺依曼结构的机器,遵循“存储程序”的概念。数据处理以存储为前提,在编程中数据如何“存得进去,取得出来”,并且符合空间、时间效率的要求,在考虑数据结构和算法时,都要有清晰的内存映像的图景。

你可以想像在定义一个结构体时,就是在构建一块内存空间的架构。当定义结构体变量时,就会实际分配内存空间,这块内存空间的首地址就是结构体变量的名称,各成员变量名对应各小块空间的首地址。访问各成员变量使用的点号,就如同是大块空间的地址到成员空间的映射或偏移。

如以下定义的结构体:

#include<iostream> struct Readout { char hour; int value; char seq; }testSize; void main() { std::cout<<sizeof(testSize); //12 }

你可能会想到以下的内存映像图景(以下都是假设32位,int类型占用4个字节长度的机器):

c语言结构体没赋值会占内存吗(C了解结构体的内存对齐)(1)

可能会认为以下代码的输出应该是6(各成员大小的和)。

std::cout<<sizeof(testSize);

但实际的输出却是12。这就是结构体的内存对齐,编译器会自动对齐结构体数据成员以提高运行效率。

结构体的字节对齐是指编译器在为结构体变量分配内存时,保证下一个成员的偏移量为成员类型的整数倍。因此,对于一些结构体变量来说,其大小并不等于结构体中每一个成员大小的总和。编译器基于效率因素增加一些额外字节以使存储边界对齐。

这样会在内存中留下一些“空洞”而增加了内存空间的占用:

c语言结构体没赋值会占内存吗(C了解结构体的内存对齐)(2)

这也就解释了内存空间占用是12而不是6的原因。

您可以通过简单地按大小(首先是最大的成员)对成员排序来最小化浪费的空间。

struct Readout { int value; char hour; char seq; }testSize; void main() { std::cout<<sizeof(testSize);//8 }

此时的内存占用是8个字节:

c语言结构体没赋值会占内存吗(C了解结构体的内存对齐)(3)

也就是说,因为对齐的原因,还是留下了一些内存“空洞”。

如果是以下结构定义,size也是8: struct Readout { char hour; char seq; int value; }testSize;

通过以下语句可以强制地声明结构体内存对齐的长度,如:

#pragma pack(1) //C编译器按n字节对齐。

如果有声明以上语句,则下面语句的输出就是6了:

std::cout<<sizeof(testSize);//6

c语言结构体没赋值会占内存吗(C了解结构体的内存对齐)(4)

基本的规则是:

结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要,编译器会在成员之间加上填充字节;

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

-End-

,