C语言笔记(自定义类型:结构体、枚举、联合体 )

前言

        本文对自定义类型的结构体创建、使用、结构体的存储方式和对齐方式,枚举的定义、使用方式以及联合体的定义、使用和存储方式展开叙述,如有错误,请各位指正。

目录

前言

1 结构体

1.1 结构体的声明

1.2 结构体的自引用

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

1.4 结构体变量的内存对齐

1.5 修改默认对齐数

1.6 结构体传参

2.位段

2.1 位段的内存分配

2.2 位段的跨平台问题

3.枚举

3.1枚举类型的定义

3.2枚举的优点

3.3枚举的使用

4. 联合(共用体)

4.1 联合类型的定义

4.2 联合的特点

4.3 联合大小的计算

1 结构体

结构体是一些值的集合,这些值称为成员变量,结构的每一个成员可以是不同类型的变量。

1.1 结构体的声明
struct tag
{
member-list;
}variable-list;

tag                结构体标签

member-list  成员列表

variable-list   变量列表

注意:创建结构提变量的时候最后的不能丢掉

结构体就创建一个自定义的包含多种数据类型的数据类型

示例

创建一个描述学生的结构体数据类型 Stu 

struct Stu
{char name[20];int age;char sex;char id[20];
};

特殊声明 :匿名结构体类型,没有结构体的标签,没有给结构体起名字。

示例1(创建没有标签的结构体)

struct
{int a;char b;float c;
}x;//x创建的结构体变量

        这种结构的使用只能现创现用,在不同的位置是无法创建同一类型的结构体变量的,创建变量需要结构体标签,没有标签就是创建不了变量了。

示例2(创建结构体的指针)

struct
{
int a;
char b;
float c;
} *p;

示例1和示例2中下方等式成立吗?

p = &x;

1.2 结构体的自引用

        结构体的自引用就是结构体中包含结构体的指针。

示例:在数据结构中数据的存放有链表性结构,链表中的每一处的节点都会存放一个数据,还可以根据节点找到下一个节点的地址,然后创建结构体;那么我结构体存放节点的数据和指向下一个节点的指针就可以了,这就是结构体的自引用了。

struct Node
{int data;//            节点的数据struct Node* next;//   下一个节点的地址
};

        结构的创建变量的时候名字较为复杂还有 unsigned int 、unsigned char等等 都可以使用 typedef重新定义名字,这样在创建变量的时候就简单了,如下

//重新定义变量
typedef unsigned int uint;
typedef unsigned char uchar;
typedef char u8;
typedef struct Stu Stu;
//创建变量
unit a;
unchar b;
u8 c;
Stu x;

需要注意

在结构体创新命名的时候,需要结构体有标签。

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

        结构体定义就是创建结构体变量,以下是创建结构提变量的方式:


//方式1 创建结构体的时候创建全局变量
struct Point
{int x;int y;
}a1;
//方式2
struct Point a2;
//方式3
int main()
{struct Point a3;return 0;
}

        初始化和和数组的初始化较为相似,是应用{ }来初始换结构体创建的变量,在后面附上值就可以了,完全初始化,

struct Point
{int x;int y;
}a1 = {10,20};
struct Point a2 = {5,9};int main()
{struct Point a3 = { 2,3 };return 0;
}

        不完全初始化(一个一个的给变量赋值)

struct S s1= { .num=10,.ch='q',.p.x=6, .p.y=10 };

嵌套结构体的初始化,有几个结构体就用几个{ }来创建变量,示例如下:

struct Point1
{int x;int y;
};
struct Point2
{int z;char ch;struct Point1 a1;float d;
};
int main()
{struct Point2 s = { 1,'a',{1,2},6.14f };return 0;
}

结构体的访问方式,分为两种,一种是使用 . 符号来访问,一种是使用 -> 符号来访问

struct Point
{int x;int y;
};
struct S
{int num;char ch;struct Point p;float d;
};int main()
{//	初始化struct S s = { 3,'w',{1,2},3.15f };//访问printf("%d %c %d %d %0.1f\n", s.num,s.ch,s.p.x, s.p.y, s.d);return 0;
}
struct Stu
{char name[20];int age;char sex[20];float score;
};
int main()
{//打印结构体信息struct Stu s = { "张三", 20, "男", 95.0f };struct Stu *ps = &s;printf(" %s %d %s %.1f\n", ps->name, ps->age, ps->sex, ps->score);return 0;
}
1.4 结构体变量的内存对齐

        结构体的内存对齐决定了结构体的在内存中所占用的空间大小。

引入

        创建两个结构体,结构体中的变量类型相同,但是顺序不同,其内存大小一样吗?

struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};
int main()
{printf("%d\n", sizeof(struct S1));//12printf("%d\n", sizeof(struct S2));//8return 0;
}

1.结构体的顺序不一样,内存不一样;

2.内存的大小和成员的数据类型有关吗?

结构体的对齐方式按照以下几条

1.结构体的第一成员,对齐到结构体在内存中的存放位置的0偏移处;

2.从第二个成员开始,每个成员都要对齐到(一个对齐数)的整数倍处;

对齐数:结构体成员自身大小和默认对齐数的较小值;

VS:默认对齐数为8;

Linux gcc :没有默认对齐数,对齐数就是结构题成员的自身大小;

3.结构体的总大小,必须是所有成员的对齐数中最大对齐数的整数倍。

4.如果结构体中嵌套了结构体成员,要将嵌套的结构体成员的对齐到自己的成员中最大的对齐数的整数。(结构体的总大小必须是最大对齐数的整数倍,包含请嵌套结构体成员的对齐数,是所有对齐数的最大值)

S1的结构体存储的方式

struct S1
{char c1;int i;char c2;
};

 (1)c1是第一个成员,从0偏移量存储,占用一个字节(灰色);

(2)i为整型变量,对齐数为4,默认对齐数为8,取较小值为4,偏移量为4,偏移量 1,2,3处内存浪费掉了(黄色);

(3)c2字符变量,对齐数为1,默认对齐数为8,取较小值为1,占用偏移量为8的位置(红色);

(4)确定结构体的大小,从c1到c2处,占用了9个字节的空间,取结构体成员的最大对齐数4,因此内存要占用12个字节,浪费6个字节(蓝色)。

S1的结构体存储的方式

struct S2
{char c1;char c2;int i;
};

(1)c1是第一个成员,从0偏移量存储,占用一个字节(灰色);

(2)c2字符变量,对齐数为1,默认对齐数为8,取较小值为1,偏移量是对齐数的倍数 2,占用偏移量为2的位置(红色);

(3)i为整型变量,对齐数为4,默认对齐数为8,取较小值为4,偏移量为4,去偏移量的倍数 4,偏移量 2,3处内存浪费掉了(黄色);

(4)确定结构体的大小,取结构体成员的最大对齐数4,因此内存要占用8个字节,浪费2个字节空间(蓝色)。

使用 offsetof函数来验证上述的偏移量是否正确,这个函数就是计算偏移量的,头文件是stddef,

验证程序

struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};
int main()
{printf("%d\n", sizeof(struct S1));//12printf("%d\n", offsetof(struct S1, c1));//0printf("%d\n", offsetof(struct S1,i));//4printf("%d\n", offsetof(struct S1,c2));//8return 0;
}

嵌套结构体内存对齐,

#include <stdio.h>
#include <stddef.h>
struct S2
{char c1;char c2;int i;
};
struct S3 
{double d;struct S2 s2;int a;
};
int main()
{printf("%d\n", sizeof(struct S3));//24printf("%d\n", offsetof(struct S3,d));//0printf("%d\n", offsetof(struct S3,s2));//8printf("%d\n", offsetof(struct S3,a));//16return 0;
}

S3是如何对齐呢?

struct S3 
{double d;struct S2 s2;int a;
};

(1)d是第一个成员,从0偏移量存储,占用8个字节(灰色);

(2)s3为结构体变量,结构体成员最大的对齐数为4,默认对齐数为8,取较小值为4,偏移量是对齐数的倍数 8,占用偏移量为8的位置(黄色);

(3)a为整型变量,对齐数为4,默认对齐数为8,取较小值为4,偏移量取16,取偏移量的倍数 16(黄色);

(4)确定结构体的大小,取结构体成员的最大对齐数8,因此内存要占用24个字节,浪费4个字节空间(蓝色)。

为什么要对齐呢?

1. 程序移植: 不是所有的平台数据的存储方式和访问方式是一样的。
2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总结:结构体的对齐就是利用内存换取运行时间的手段。

如何节省空间?

        将占用空间小的成员集中到一起。

1.5 修改默认对齐数
#pragma pack()//恢复默认对齐数
#pragma pack(1)//设置对齐数为1
#include <stdio.h>
#include <stddef.h>
#pragma pack(1)//设置对齐数为1
struct S1
{char c1;int i;char c2;
};
#pragma pack()//恢复默认对齐数int main()
{printf("%d\n", sizeof(struct S1));//6printf("%d\n", offsetof(struct S1,c1));//0printf("%d\n", offsetof(struct S1,i));//1printf("%d\n", offsetof(struct S1,c2));//5return 0;
}

此时S1的空间对齐方式

(1)c1是第一个成员,从0偏移量存储,占用一个字节(灰色);

(2)i为整型变量,对齐数为1,偏移量为1,(黄色);

(3)c2字符变量,对齐数为1,占用偏移量为5的位置(红色);

(4)确定结构体的大小,从c1到c2处,占用了6个字节的空间。

1.6 结构体传参

        结构体传参一般采用地址传参的方式,在传递值传参的时候,需要重新创建变量,浪费大量的内存空间,传址调用较为省空间。

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;
}

2.位段

位段的声明和结构体类似,有两种不同的标志

1.位段的成员必须是 int 、unsigned int、或者是signed int;

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

struct A
{int _a:2;int _b:5;int _c:10;int _d:30;
};

A是一个位段类型,位段的大小是多少呢?

printf("%d", sizeof(struct A));//8

原本4个整型数据,占据16个字节,如何在内存中限制到8个字节的呢?

2.1 位段的内存分配

1. 位段的成员可以是 int unsigned、 int、 signed int 、 char 类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

struct S
{char a:3;char b:4;char c:5;char d:4;
};struct S s = {0};s.a = 10;s.b = 12;s.c = 3;s.d = 4;

        位段开辟空间一次开辟一个字节,不够使用的话再开辟另一个字节;位段是从低地址到高地址存储的,在每个字节中也是从低位向高位存储;

2.2 位段的跨平台问题

1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的。

特点:位段和结构体相比,位段的存储空间为共用空间,位段更加节省空间,但是存在跨平台问题。

3.枚举

3.1枚举类型的定义

可以被一一列举的变量,语法形式和结构体类似,例如生活中的,

1.一周的星期一到星期日有限的7天,可以一一列举;

2.性别有:男、女分别;

3.一年有12个月,可以一一列举。

enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
enum Sex
{MALE,FEMALE,SECRET
};

三原色

enum Color
{RED,GREEN,BLUE};

上述是有可能取到的值,默认从零开始一次递增,在定义的时候可以赋初值,示例

#include <stdio.h>
enum Day
{Mon = 1,Tues = 2,Wed = 3,Thur = 4 ,Fri = 5,Sat = 6,Sun = 7 
};
int main()
{printf("%d\n", Mon);//1printf("%d\n", Tues);//2return 0;
}

        枚举常量就是给特定的字符赋予一定的数值,在后续的使用中Mon和1等价。

3.2枚举的优点

和#define相比枚举创建的常量可以在调试中显示,而宏定义是不可以的。

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

3.3枚举的使用

下述代码是用于C51单片机的按键控制LED亮灭的程序,创建的枚举变量使用的时候程序较好理解,如果将KEY1_PRESS为1的话,并不是特别的直观的表达出按键1以将按下。

#include <REGX52.H>
#include <stdio.h>
//引脚定义
#define  SMG_A_DP_PORT  P1 
sbit KEY1 = P0 ^ 0;
sbit KEY2 = P0 ^ 1;
sbit KEY3 = P0 ^ 2;
sbit KEY4 = P0 ^ 3;
sbit LED1 = P2 ^ 0;
sbit LED2 = P2 ^ 1;
sbit LED3 = P2 ^ 2;
sbit LED4 = P2 ^ 3;enum KEY
{KEY_UNPRESS = 0,KEY1_PRESS = 1,KEY2_PRESS = 2,KEY3_PRESS = 3,KEY4_PRESS = 4,
};//枚举
char key_scan(mode);//当mode=0的时候 单次扫描 mode=1 连扫
void main()
{unsigned char  ret = 0;while (1){ret = key_scan(0);switch (ret){case KEY1_PRESS:{LED1 = !LED1;break;}case KEY2_PRESS:{LED2 = !LED2;break;}case KEY3_PRESS:{LED3 = !LED3;break;}case KEY4_PRESS:{LED4 = !LED4;break;}}}}//延时函数 当1=ten_us,延时10us
void delay_10us(unsigned int ten_us)
{while (ten_us--);
}
char key_scan(mode)//当mode=0的时候 单次扫描 mode=1 连扫
{static char key = 1;if (mode){key = 1;}if (key == 1 && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)){key = 0;delay_10us(1000);if (KEY1 == 0)return KEY1_PRESS;else if (KEY2 == 0)return KEY2_PRESS;else if (KEY3 == 0)return KEY3_PRESS;else if (KEY4 == 0)return KEY4_PRESS;}else if (KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1){key = 1;}return KEY_UNPRESS;
}

4. 联合(共用体)

4.1 联合类型的定义

联合是一种特殊的自定义类型,定义的变量也包含一系列的成员这些成员会共用一块内存空间。

union UN 
{char c;int i;
};
int main()
{union UN un;printf("%d\n", sizeof(un));//4printf("%p\n", &un);//00EFFB08printf("%p\n", &(un.c));//00EFFB08printf("%p\n", &(un.c));//00EFFB08return 0;
}

        三次取地址的结果是一样的,说明c和i的起始地址的是一样,可以得出,两个变量占用得空间开始是一样得,当然两个变量是不可以同时使用得,c占用4个字节的第一个字节,i占用四个字节,如图

4.2 联合的特点

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

int main()
{union Un{int i;char c;};union Un un;//下面输出的结果是什么?un.i = 0x11223344;un.c = 0x55;printf("%x\n", un.i);//11223355return 0;
}

        un的前四个字节为11223344,后有将44修改为了55,因为VS2017上位小端存储。

可以封装成函数判断大小端存储:

#include<stdio.h>
int check_sys()
{union Un{int i;char c;}un;un.i = 1;return un.c;//判断变量,低位是否为1或者0
}
int main()
{int ret = check_sys();if (ret){printf("小端存储");}elseprintf("大端存储");return 0;
}
4.3 联合大小的计算

1.联合的大小至少是最大成员的大小。
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

int main()
{union Un1{char c[5];int i;};union Un2{short c[7];int i;};//下面输出的结果是什么?printf("%d\n", sizeof(union Un1));//8printf("%d\n", sizeof(union Un2));//16
}

Un1的内存大小为8

(1).c[5]的对齐数位1,占用5个字节的空间

(2).i的对齐数为4,占用内存4个字节的空间,

(3)最大对齐数为4,再取4的倍数,内存大小为8个字节;

Un2的内存大小为16

(1).c[7]的对齐数位2,占用14个字节的空间

(2).i的对齐数为4,占用内存4个字节的空间,

(3)最大对齐数为4,再取4的倍数,内存大小为16个字节;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/61983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全问题与大忌

“老三样&#xff0c;堵漏洞、做高墙、防外攻&#xff0c;防不胜防。” 日前&#xff0c;中国工程院沈昌祥院士这样概括中国信息安全的基本状况。 信息安全提了这么些年&#xff0c;究竟国内的网络如何脆弱&#xff0c;如何不堪一击&#xff0c;恐怕常人是难以想象的。公安部计…

3.langchain中的prompt模板 (few shot examples in chat models)

本教程将介绍如何使用LangChain库和智谱清言的 GLM-4-Plus 模型来理解和推理一个自定义的运算符&#xff08;例如使用鹦鹉表情符号&#x1f99c;&#xff09;。我们将通过一系列示例来训练模型&#xff0c;使其能够理解和推断该运算符的含义。 环境准备 首先&#xff0c;确保…

【消息序列】详解(6):深入探讨缓冲区管理与流量控制机制

目录 一、概述 1.1. 缓冲区管理的重要性 1.2. 实现方式 1.2.1. HCI_Read_Buffer_Size 命令 1.2.2. HCI_Number_Of_Completed_Packets 事件 1.2.3. HCI_Set_Controller_To_Host_Flow_Control 命令 1.2.4. HCI_Host_Buffer_Size 命令 1.2.5. HCI_Host_Number_Of_Complete…

如何使用OCR技术批量识别图片中的文字并重命名文件,OCR 技术批量识别图片中的文字可能出现的错误

字符识别错误 形近字混淆&#xff1a;例如 “已” 和 “己”、“未” 和 “末” 等&#xff0c;由于外形极为相似&#xff0c;OCR 软件在识别时可能出现误判&#xff0c;将原本正确的字识别成与之形近的另一个字。比如在识别一篇手写的文章中&#xff0c;手写体的 “已” 可能就…

Qt | 开发技能提升档次哈

点击上方"蓝字"关注我们 01、Creator常用快捷键 >>> F1 查看帮助 F2 跳转到函数定义 Shift+F2 声明和定义之间切换 F3 查找下一个 F4 头文件和源文件之间切换 Ctrl+1 欢迎模式 Ctrl+2 编辑模…

kafka消费者组和分区数之间的关系是怎样的?

消费者组和分区数之间的关系决定了Kafka中消息的消费方式和负载均衡。合理配置分区数和消费者数量对于优化Kafka的性能和资源利用率至关重要。以下是这种关系的几个关键点&#xff1a; 一个分区只能被同一组的一个消费者消费&#xff1a;这是为了保证消息的顺序性。在同一个消费…

Element Plus的快速入门

一、什么是Element Plus Element : 是饿了么团队研发的&#xff0c;基于Vue3&#xff0c;面向设计师和开发者的组件库。 组件&#xff1a;组成网页的部分&#xff0c;例如超链接&#xff0c;按钮&#xff0c;图片&#xff0c;表格&#xff0c;表单&#xff0c;分页条等等。 …

健身房小程序服务渠道开展

健身不单单是锻炼身体、保持身材&#xff0c;也是一种社交方式&#xff0c;城市里门店不少&#xff0c;每家都有一定流量和老客&#xff0c;但仅靠传统线下拉客/自然流量前往和线上朋友圈、短视频发硬广等方式还不够。 商家需要找到更多潜在目标客户&#xff0c;而消费者也对门…

MRI联合超声影像学预测乳腺癌分子水平表达

MRI联合超声影像学预测乳腺癌分子水平表达的研究是一个跨学科的方向,涉及医学影像学、分子生物学和计算机视觉等领域。目标是通过影像学手段(如MRI和超声)来预测乳腺癌的分子标志物,进一步了解肿瘤的生物学特征,并辅助诊断、预后评估以及治疗方案的选择。 一、可能的研究…

网络渗透测试工具推荐与简介

推荐一批网络渗透测试工具&#xff1a; AIEngine - 这是一个基于Python/Ruby/Java/Lua的互动/可编程的下一代数据包检测引擎&#xff0c;具有无需人工干预的学习功能&#xff0c;支持网络入侵检测系统(NIDS)、DNS域名分类、网络数据收集、网络专家分析等功能。 Denyhosts - 用…

Docker--通过Docker容器创建一个Web服务器

Web服务器 Web服务器&#xff0c;一般指网站服务器&#xff0c;是驻留于因特网上某种类型计算机的程序。 Web服务器可以向浏览器等Web客户端提供文档&#xff0c;也可以放置网站文件以供全世界浏览&#xff0c;或放置数据文件以供全世界下载。 Web服务器的主要功能是提供网上…

HTMLCSS:3D金字塔加载动画

效果演示 这段代码通过CSS3的3D变换和动画功能&#xff0c;创建了一个旋转的金字塔加载动画&#xff0c;每个侧面都有不同的颜色渐变&#xff0c;底部还有一个模糊的阴影效果&#xff0c;增加了视觉的立体感。 HTML <div class"pyramid-loader"><div cl…

C++中定义类型名的方法

什么是 C 中的类型别名和 using 声明&#xff1f; 类型别名与using都是为了提高代码的可读性。 有两种方法可以定义类型别名 一种是使用关键字typedef起别名使用别名声明来定义类型的别名&#xff0c;即使用using. typedef 关键字typedef作为声明语句中的基本数据类型的一…

Java 查询最大最小值 详解

在 Java 中&#xff0c;查询最大值和最小值是常见需求。以下将详细介绍 最大值和最小值的查询方法&#xff0c;包括适用于数组、集合、以及更复杂的数据结构的解决方案。 1. 使用 Math 类 Java 提供了 Math.max 和 Math.min 方法&#xff0c;可用于直接比较两个值。 适用场景…

git标签和分支

在 Git 中&#xff0c;标签&#xff08;Tag&#xff09;和分支&#xff08;Branch&#xff09;都是用来标识代码快照的工具&#xff0c;但是它们有着不同的用途和行为方式。 分支&#xff08;Branch&#xff09; 目的&#xff1a;分支主要用于开发过程中的不同功能或版本的开…

selinux及防火墙

selinux说明 SELinux 是 Security-Enhanced Linux 的缩写&#xff0c;意思是安全强化的 linux 。 SELinux 主要由美国国家安全局&#xff08; NSA &#xff09;开发&#xff0c;当初开发的目的是为了避免资源的误用。 httpd进程标签&#xff08;/usr/share/nginx/html &#…

vue 富文本图片如何拖拽

在Vue项目中实现富文本编辑器&#xff08;如vue-quill-editor&#xff09;的图片拖拽功能&#xff0c;需要结合Quill.js及其相关插件进行配置 安装必要的依赖包&#xff1a; 你需要安装vue-quill-editor作为富文本编辑器的基础组件。为了支持图片拖拽功能&#xff0c;你还需要…

秋招面试基础总结,Java八股文基础(串联知识),四万字大全

目录 值传递和引用传递 静态变量和静态代码块的执行顺序 Java​​​​​​​集合的框架&#xff0c;Set,HashSet,LinkedHashSet这三个底层是什么 多线程篇 Java实现多线程的方式 假设一个线程池&#xff0c;核心线程数是2&#xff0c;最大线程数是3&#xff0c;阻塞队列是4…

MySQL原理简介—12.MySQL主从同步

大纲 1.异步复制为MySQL搭建一套主从复制架构 2.半同步复制为MySQL搭建一套主从复制架构 3.GTID为MySQL搭建一套主从复制架构 4.并行复制降低主从同步延迟或强制读主库 1.异步复制为MySQL搭建一套主从复制架构 (1)MySQL主从复制的原理 (2)搭建主从复制架构的配置 (1)MySQ…

一文了解Spring提供的几种扩展能力

基于 spring bean 的扩展 1. BeanPostProcessor spring 提供的针对 bean 的初始化过程时提供的扩展能力&#xff0c;从方法名也很容易看出&#xff0c;提供的两个方法分别是为 bean 对象提供了初始化之前以及初始化之后的扩展能力。 package com.wyl.conf;import org.spring…