一、结构体(struct):是由一系列相同类型或不同类型的数据构成的数据集合。
1.声明一个结构体的一般形式,如
struct Student //struct 结构体名
{
int age; //成员列表
char name[20];
char sex;
char addr[30];
};
2.结构的定义
(1)先声明结构体类型在定义结构体变量
如上面已定义了一个结构体类型变量,然后定义结构体变量。如
struct Student student1,student2;
(2)在声明类型的同时定义结构体变量
如
struct student
{
int age;
char name[20];
char sex;
char addr[30];
}student1,student2;
3.结构体变量的初始化
(1)在定义时指定初始值。如
struct Student
{
int age;
char name[20];
char sex;
char addr[30];
}student1 = {22,"lihua",'m',"陕西省神木县"};
(2)也可以采取声明类型与定义变量分开的形式
struct Student student2 = { 24, "wangwu", 'm', "8B公寓" };
4.结构体的typedef
typedef 是C语言中的一个关键字,是类型定义的意思,typedef struct 是为了使用结构体更方便。如
typedef struct Student
{
int age;
char name[20];
char sex;
char addr[30];
}stu;
在定义结构体变量时,struct Student student1相当于stu student1。
5.结构体的存储
结构体在内存中的存储的大小不是单纯的把所有类型的字节数相加,而是按内存对齐的方式来存储的。
(1)对齐原因主要来自两个方面
a)平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只
能在某些地址处取某些特定类型的数据,否则抛出数据异常。
b)性能原因:数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐的
内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
struct Student
{
char name;
int age;
};
若不存在内存对齐,则系统访问结构体成员为一个整型时,访问int的变量内容需要作两次访问。
(2)对齐规则
①结构的第一个成员永远放在结构体的0偏移处。
②从第二个成员开始,都要对齐到 某个对齐数的整数倍处。对齐数为结构成员自身大小和 默认对齐数的最小值(每个编译器都有自己的默认对齐数)。
③结构体的总大小必须是最大对齐数的整数倍。
④如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数的整数倍。
☆程序员可以通过预编译命令#pragma pack(n) n=1,2,4,8,16来改变对齐数。
计算结构体的内存大小,如
struct Student //VS默认对齐数为8
{
char name; //char占用一个字节,放在0偏移处
int age; //它的对齐数为4,所以1,2,3偏移处浪费,4偏移是对齐数的整数倍,从4偏移开始存,4,5,6,7偏移存整型
double score; //它的对齐数为8,8偏移处正好是对齐数的整数倍,从8偏移开始存,8,9,10,11,12,13,14,15偏移从双精度浮点型
char sex; //它的对齐数为1,16偏移处正好是对齐数的整数倍,16偏移处存字符型
}; //根据第三条规则,结构体的总大小是最大对齐数的整数倍,17个字节不是最大对齐数的整数倍,所以浪费7个字节
//最后大小为24个字节
二、位段。
C语言允许在一个结构体中以比特位为单位来指定其成员所占内存长度,这种以位为单位的成员称为位段,使用位段可以节省空间。
位段的声明必须是int,signed int或unsigned int。在成员名的后面是一个冒号和一个整数。需要说明的是一个位段必须存储在
同一存储单元中,不能跨两个单元。如果第一个单元所剩空间不够存放另一位位段时,应从下一单元存放该位段。位段的长度不能
大于指定类型的长度,如int的位段的长度不能超过32。结构体中不能定义位段数组。
1.结构体实现位段
struct Student
{
int a : 5; //位段a,占5位
signed int b : 2; //位段b,占2位
unsigned int : 0; //无名位段,占0位,无名位段不能被访问但是会占据空间,C中占0字节,C++占1字节
unsigned int c : 4;
};
2.位段大小的计算
一个位段结构所占的空间至少是一个位段存储单元的大小。若位段占得位数为0,则这个位段必须是无名位段,下一个位段从下一个位段
存储单元开始存放。
3.位段的数据存储及跨平台问题
位段为什么不能跨平台呢?当一个结构体声明了两个位段,第二个位段较大,无法容纳在第一个位段剩余位时,编译器有可能把第二个位段
存储在内存的 下一个字节中,也有可能存储在第一个位段的后面,从而在两个内存位置上形成重叠,还有位段在内存中是从前向后,
还是从后向前是不同的,所以位段不能跨平台。(这个也是位段计算大小的方法,在VC操作环境下,第二个位段较大会存储在下一个字节中,
位段是从后向前存储的)