1、简单地声明一个结构体和定义结构体变量( 二 )


当然如果可以直接拿到结构体变量的话 , 使用变量来访问结构体成员会更直观点 。
五. 结构体大小的计算 1. 计算方法
结构体的大小不是结构体元素单纯相加就行的 , 因为我们现在主流的计算机使用的都是64位字长的CPU , 对这类型的CPU取8个字节的数要比取一个字节要高效 , 也更方便 。所以在结构体中每个成员的首地址都是8的整数倍的话 , 取数据元素时就会相对更高效 , 这就是内存对齐的由来 。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数) 。程序员可以通过预编译命令# pack(n)来改变这一系数 , 其中的 n 就是你要指定的“对齐系数” 。
但实际每个成员的类型可能是不同的 , 每个类型对应不同大小 , 为了更高效地读取结构体变量的成员 , 结构体的大小要遵循一套对齐规则:
第一个成员在与结构体变量偏移量为0的地址处 。(即结构体的首地址处 , 即对齐到0处)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处 。结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍 。如果嵌套了结构体 , 嵌套的结构体对齐到自己的最大对齐数的整数倍处 , 结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍 。
对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值 。
PS:VS中的默认对齐数为8 , 不是所有编译器都有默认对齐数 , 当编译器没有默认对齐数的时候 , 成员变量的大小就是该成员的对齐数 。
2. 普通结构体
第一步:找出每个成员变量的大小将其与编译器的默认对齐数相比较 , 取其较小值为该成员变量的对齐数
PS:这里使用的是VS编译器 , 故默认对齐数为8 。
第二步:根据每个成员对应的对齐数画出它们在内存中的相对位置
第三步:通过最大对齐数决定最终该结构体的大小
通过图我们可以知道 , 绿色部分( d成员占用)+红色部分(char c成员占用)+紫色部分(int i成员占用)+红色与紫色之间的白色部分(浪费掉了)总共占用了16个字节的内存空间 。
我们需要将它们总共占用的内存空间(16)与结构体成员的最大对齐数(8)相比较 , 结构体的总大小为最大对齐数的整数倍 , 此时16正好是8的整数倍 , 所以该结构体在VS编译器下的大小就16个字节 。即创建一个该类型的结构体变量 , 内存需为其开辟16个字节的内存空间 。
PS:大多数情况下 , 成员变量已经占用的总字节个数并不一定正好为其成员变量中的最大对齐数的整数倍 , 这时我们需要将其扩大为最大对齐数的整数倍 。
3. 包含数组成员的结构体
数组应拆开来看 , 不能看做一个整体
struct S{char a; //对齐数为1 。占1个字节char c[5]; //对齐数为1 。可看成5个char占5个字节int b; //对齐数为4 。占4个字节 , 因为前面所有成员占6个字节 , 不是4//个字节的整数倍 , 所以在第二个成员和第三个成员//之间要补2个字节} //所以该结构体的大小为1+5+2(补)+4=12个字节
4. 成员包含结构体的结构体
1)如果结构体成员只是说明而没有定义变量 , 则这个结构体成员不占内存空间 。
struct S{char a; //对齐数为1 。占1个字节struct s{int c;char d;}; //此处结构体只声明 , 没有定义结构体变量 , 所以该声明//的结构体在地址空间中并不占位置int f; //对齐数为4 。占4个字节double b; //对齐数为8 , }; //该结构体的大小为1+3(补)+4+8=16个字节