Struct结构体是 C/C++ 语言中用来自定义数据类型的,
我们学习结构体知识,除了学习一些相关的基本知识外,我们必须了解其在计算机内部具体的存在,主要问题集中在结构的大小以及内存的分配问题
一、 字节对齐
现代 计算机 中内存空间都是按照byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 我们拿 32位系统来说(以下内容均对于 32 位系统),按我的理解比如一个 char 型变量 c 之后我们接着需要存储一个 int 型的变量 i 假如 c 变量的首地址是 0x0044ff33 ,那么变量 i 虽然一定存储在 0x0044ff33 之后,但是其首地址一定不会是 0x0044ff34 ,而会是 0x0044ff38 ,因为这样对于计算机的内部处理将更加的方便和快捷。
二、 结构体大小及内存分配
我们举两个例子来讨论:
1、 struct Demo
{
char c;
int i;
};
struct Demo demo1;
那么我们提出问题:sizeof ( demo1 ) = ?
&demo1 = ?
&demo1.c = ?
&demo.i = ?
答案: sizeof ( demo1 ) = 8 字节
&demo1 = 0x0022ff48
&demo1.c = 0x0022ff48
&demo1.i = 0x0022ff4c
根据编译器的不同,对于地址空间:0x0022ff48 — 0x0022ff4c 做不同处理,有的填充随机字符(如 VC ,会在这里填充 CC CC CC ),而有的编译器也有不同处理,比如填 0 或者空着
2、 struct Demo
{
int i;
char c;
int j;
};
struct Demo demo2;
那么我们提出问题:sizeof ( demo2 ) = ?
&demo2 = ?
&demo2.i = ?
&demo2.c = ?
&demo2.j = ?
答案: sizeof ( demo2 ) = 12 字节
&demo2 = 0x0022ff44
&demo2.i =0x0022ff44
&demo2.c = 0x0022ff48
&demo2.j =0x0022ff4c
根据编译器的不同,对于地址空间:0x0022ff48 — 0x0022ff4c 做不同处理,有的填充随机字符(如 VC ,会在这里填充 CC CC CC ),而有的编译器也有不同处理,比如填 0 或者空着
3、 struct Demo
{
int i;
char c;
};
struct Demo demo3;
那么我们提出问题:sizeof ( demo3 ) = ?
&demo3 = ?
&demo3.i = ?
&demo3.c = ?
答案: sizeof ( demo3 ) = 12 字节
&demo3 = 0x0022ff44
&demo3.i = 0x0022ff44
&demo3.c = 0x0022ff48
根据编译器的不同,对于地址空间:0x0022ff49 — 0022ff4c 做不同处理,有的填充随机字符(如 VC ,会在这里填充 CC CC CC ),而有的编译器也有不同处理,比如填 0 或者空着这与上面两个不同,因为缺口在后面,但是本质意义是相同的。、
三、 规则
其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;例如上面第 一 结构体变量的地址空间。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。例如上面第 三 结构体变量。