自定义类型(结构体,枚举,联合)超详细讲解

结构体的声明

1.
```c
struct s
{
    
    
	int a;
	char arr[10];
	char b;
};
struct s
{
    
    
	int a;
	char arr[10];
	char b;
}a, b, c;

a, b, c为struct s 类型全局变量
3.

typedef struct book
{
    
    
	int a;
	char arr[10];
	char b;
}book;

``
三种声明均可

匿名结构体类型

匿名结构体会省略结构体标签

struct 
{
    
    
	char a;
	char arr[10];
}a;
struct 
{
    
    
	char a;
	char arr[10];
}*p;

int main()
{
    
    
	p = &a;
	return 0;
}
typedef struct 
{
    
    
	char a;
}node;
int main()
{
    
    
	node s = {
    
     'a' };
	printf("%c", s.a);
	return 0;
}

但省略了结构体标签后,编译器会把以上两种类型当作完全不一样的类型,p = &a时会报错
在这里插入图片描述

结构体的自引用

struct node
{
    
    
	char a;
	struct node* next;
};

切记要用指针进行自引用,若写成结构体本身会陷入死循环

typedef struct
{
    
    
int data;
Node* next;
}Node;

在创建next变量之前,typedef还没有把匿名结构体重命名为Node,所以这种方法不可行

结构体变量的定义以及初始化

typedef struct book
{
    
    
	int a;
	char arr[10];
	char b;
}book;
typedef struct book 
{
    
    
	int a;
	char arr[10];
	char b;
}book;
void print(book *b1)
{
    
    
	printf("%d %s %c", b1->a, b1->arr, b1->b);
}
int main()
{
    
    
	book b1 = {
    
     10,"我爱代码",'a' };
	book b2 = {
    
     .b = 56,.arr = "代码爱我",.b = 'b' };
	print(&b1);
}

结构体内存对齐(重点)

结构体对齐规则
1.第一个结构体成员在结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个对齐数整数倍
3.对齐数为结构体变量本身的一个对齐数和编译器默认对齐数的较小值
4.结构体总大小为最大对齐数的整数倍
5.如果嵌套了结构体,嵌套的结构体要对齐到自身结构体最大对齐的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

struct s2
{
    
                //a的对齐数 默认对齐数	对齐数
	double a;//8			8		  8
	
	int b;   //b的对齐数 默认对齐数	对齐数
			 //4			8		  4
	char c;  //c的对齐数 默认对齐数	对齐数
			 //1			8		  1
};
struct s1
{
    
    
	char a1; //1 8 1
	struct s2;//自身结构体对齐数的最大值8
	int b1;//4 8 4
};
int main()
{
    
    
	printf("%d\n", sizeof(struct s2));
	printf("%d\n", sizeof(struct s1));
	return 0;
}

在这里插入图片描述
在这里插入图片描述

修改默认对齐数

#pragma pack(4)//修改默认对齐数为4
#pragma pack()//取消设置的默认对齐数,还原回默认


结构体传参

结构体传参时,要尽量传结构体指针,直接传结构体本身的话,参数压栈的系统开销会很大,时间的耗费也会加大,导致性能下降

struct S
{
    
    
int data[1000];
int num;
};
struct S s = {
    
    {
    
    1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
    
    
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
    
    
printf("%d\n", ps->num);
}
int main()
{
    
    
print1(s); //传结构体
print2(&s); //传地址
return 0;
}

位段

位段的声明
位段的声明与结构体相似,但有两点不同
1.位段的成员必须是int和char相关的类型
2.位段的成员名有一个冒号,一个数字

struct A
{
    
    
	char a : 4;
	char b : 5;
};

意思是给a分配4个比特位,给b分配5个比特位
位段的内存分配
1.位段的空间是按照4个字节或1个字节的空间开辟的
2.位段有很多不确定因素,应避免跨平台应用
位段的跨平台问题
1.int位段被当成有符号类型,还是无符号不确定
2… 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,在16位机器17个比特位会出问题的)
3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义
4… 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的

枚举

枚举类型的定义

enum sex
{
    
    
	male,
	female,
	secret
};

可以给成员变量赋值,成员变量从0开始递增,若赋值,成员变量从赋的值后开始递增
枚举的优点

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 防止了命名污染(封装)
  4. 便于调试
  5. 使用方便,一次可以定义多个常量
    枚举的使用
enum sex
{
    
    
	male,
	female,
	secret
};
int main()
{
    
    
	enum sex a = male;
	return 0;
}

只能拿{}里的值即枚举常量给枚举变量a赋值,不可随便给a赋值,尽量不要给a赋值为一个数字,因为在c++文件中运行时会报错

联合(共用体)

联合类型的声明与定义

union A
{
    
    
	int a;
	char b;
};
int main()
{
    
    
	union A a;
	return 0;
}

联合的特点
联合的成员共用一块空间,这块空间的大小至少是最大成员的大小
联合大小的计算

  1. 联合的大小至少是最大成员的大小
  2. 当联合的大小不是最大对齐数的整数倍时,要对齐到最大对齐数的整数倍,这里的最大对齐数是不考虑默认对齐数的,a的对齐数为4,b为1,最大对齐数为4,联合大小为5,要是4的整数倍,所以联合的大小变为8

利用联合体判断大小端

union A
{
    
    
	int a;
	char b;
};
int main()
{
    
    
	union A u;
	u.a = 1;
	if (u.b == 1)
	{
    
    
		printf("小端");
	}
	else
		printf("大端");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wan__xia/article/details/129776687