C语言程序设计——结构体、枚举、联合

一、结构体

1. 概念

        结构体是一种自定义的数据类型,它是一些值的集合,这些值称为成员变量,结构体由多个数据成员组成,这些成员可以是不同类型的变量。

2. 结构体的声明

2.1 一般声明

struct student {
    char name[10];
    int age;
};

2.2 特殊声明

//匿名结构体类型
struct {
    char name[10];
    int age;
}s1,s2;

        匿名结构体类型,只能在声明结构体类型时,顺带创建其结构体变量,其余地方无法再创建该类型的变量。也就是只能使用一次。

注意:

        即使多个匿名结构体的成员完全一致,它们也属于不同的结构体类型。

3. 结构体的自引用

在结构体中包含一个类型为该结构体本身的成员是否可以?

struct ListNode {
	int val;
	struct ListNode next;
};

注意:这种自引用方式是不可以的,结构体的成员不能是自身类型,因为编译器无法确定结构体的大小。

正确的自引用方式:

struct ListNode {
	int val;
    //使用指针来保存自身类型成员的地址
	struct ListNode* next;
};

4. 结构体变量的定义和初始化

struct ListNode {
	int val;
	struct ListNode* next;
}n1, n2;//声明类型的同时定义变量n1,n2
//定义变量同时赋初始值
struct ListNode n3 = { 10, NULL };

5. 结构体内存对齐

5.1 结构体内存对齐规则★

(1)第一个成员在与结构体变量偏移量为0的地址处;

(2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处;

        对齐数 = min(编译器默认对齐数, 该成员变量大小)

(3)结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍;

(4)如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

5.2 为什么存在内存对齐?

(1)平台原因

        不是所有平台的硬件都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取出某些特定类型的数据。

(2)性能原因

        数据结构(尤其是栈)应该尽可能的在自然边界上对齐;因为为了访问未对齐的内存,处理器需要两次内存访问,而对于对齐的内存访问只需要一次访问。

(3)总结

        本质是因为硬件平台限制,导致数据读取可能会出现低效率问题,通过“浪费”一些空间的方式,来达到快速读取目标数据的目的。

5.3 修改默认对齐数

#pragma pack(4)//修改默认对齐数为4
struct Node {
	char ch;
	int a;
	char cr;
};
#pragma pack(8)//修改默认对齐数为8

二、位段

1. 概念

        位段是C语言中的一个特性,用于在结构体中以位为单位定义和访问数据。它允许我们对结构体成员进行精确的位级别的控制,以节省内存空间。

(1)位段成员只能是整型类型(包括有符号和无符号整数类型)或枚举类型,不能使用浮点类型、结构体类型等非整型类型;

(2)位段的成员名后有一个冒号和数字。

struct A {
	int a : 2;//表示只需要2个bit
	int b : 5;
	int c : 10;
};

2. 位段的内存分配

(1)位段在空间上是按照需要以4字节或1字节的方式来开辟的;

(2)位段涉及很多不确定因素,是不支持平台的,若是注直可移植性的程序应该避免使用位段。

3. 位段的跨平台问题

(1)int位段被当成有符号数还是无符号数是不确定的;

(2)位段中最大位的数目不能确定(比如在16位机器中最大为16,32位机器最大为32);

(3)位段中的成员在内存中是从左向右分配,还是从右向左分配,标志尚未定义;

(4)当一个结构包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余位时,是舍弃剩余位还是利用,这是不确定的。

4. 位段的应用

        多用于计算机网络中一些协议首部结构,比如:

C语言程序设计——结构体、枚举、联合_第1张图片

 三、枚举

1. 枚举类型的定义

enum day {
	mon,  // 0
	tues, // 1
	wed,  // 2
	thur, // 3
	fri,  // 4
	sat,  // 5
	sun   // 6
};

        {}中的内容是枚举类型的可能取值,也叫枚举常量。取值默认从0开始,依次递增1,如果在定义的时候赋予了初始值,则后续在此基础上依次加一。

enum day {
	mon,  // 0
	tues = 2, // 2
	wed,  // 3
	thur, // 4
	fri = 8,  // 8
	sat,  // 9
	sun   // 10
};

2. 枚举的优点

(1)增加代码的可读性和可维护性;

(2)相比较于#define定义的标识符,枚举有类型检查,更加严谨;

(3)防止命名污染;

(4)便于调试;

(5)使用方便,一次可以定义多个常量。

四、联合(共用体)

1. 联合类型的定义

        联合是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特点是这些成员共用同一块空间,所以联合也叫共用体。

union re {
	int a;
	char ch;
};

2. 联合的特点

        联合的所有成员共用同一块内存空间,一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

3. 联合大小计算

(1)联合大小至少是最大成员的大小;

(2)当最大成员大小不是最大对齐数的整数倍的时候,就需要对齐到最大对齐数的整数倍。

比如:

union {
	char arr[5];
	int i;
};

        该联合最大成员大小为5,最大对齐数是4,所以需要对齐到最大对齐数整数倍数,即该联合大小为8。

你可能感兴趣的:(C语言程序设计,c语言,开发语言)