【C语言】结构体、联合体、枚举类型的字节大小详解

news2024/11/30 7:16:00

在C语言中,结构体(struct)和联合体(union) 是常用的复合数据类型,它们的内存布局和字节大小直接影响程序的性能和内存使用。下面为大家详细解释它们的字节大小计算方法,包括对齐规则、内存分配方式及代码示例分析。

结构体(struct)

结构体的定义:
  • 结构体是一种将多个类型的变量组合在一起的复合数据类型,每个成员都有自己的存储空间。
  • 每个成员按顺序存储。
  • 目的:创建新的类型,可面向对象编程,实例化一整个对象 —> 结构体。

语法:

 struct [标签] {
 	成员属性1;
 	成员属性2;
 	成员属性3;
 	成员属性4;
 };
	// 结构体的关键字 : struct 
    // 标签 可有 可无  
    // 一个个成员都是 分号 结尾 

不带标签的定义:

struct {int a; int b; char c;};  // 有了新的类型
//定义该类型变量:
struct {int a; int b; char c;} xx;
//取别名:
typedef struct {int a; int b; char c;} yy_t;
yy_t zz;

带标签的定义:

struct point {int x; int y;}  // 创建了新的标签 
//定义类型:
struct point {int x; int y;} xx; // 创建了point标签,定义xx变量
// 使用标签:
struct point sp;   // 使用point标签,前提:必须要有point标签

typedef  struct point {int x; int y;} qq_t; // 取了个新的别名叫qq_t , 同时 创建了标签 point 
qq_t x; // 使用新的别名类型 创建变量 x 

注意事项:相同名字的标签 不可重复创建

为结构体成员赋值:

struct person 
{
    char name[20];
    int age;
    int sg;
    int tz;
    int cd;
};
struct person sp; 
// 当你拥有该类型 实例化 对象 ,取里面的成员,用 点(.)
    strcpy(sp.name,"jack");
    sp.age = 18;
    sp.sg = 180;
    sp.tz = 180;
    sp.cd = 18;
// 当你知道 该 实例化 对象 的地址的时候,取里面的成员 ,用 箭头 (->)
struct person *p = &sp;
    p->name
    p->age
    p->sg
    p->tz
    p->cd

struct person *xp = (struct person *)malloc(sizeof(struct person));
    xp->name 
    xp->age

结构体初始化的三种形式:

struct person 
{
    char name[20];
    int age;
    int sg;
    int tz;
    int cd;
};
//第一种:
    struct person sp1 = {"jack",18, 180};
    struct person sp2 = {"jack",18, 180, 180, 18};
//第二种:(内核中结构体的初始化方式)
    struct person sp3 = {
        .name = "jack",
        .cd = 18,
        .sg = 180
    };
//第三种:
    struct person sp4 = {
        name:"jack",
        cd : 18,
        sg :180
    };
内存布局

字节对齐(Alignment):

  • 在分配内存时,编译器会根据硬件架构的要求进行对齐(Alignment),确保变量的地址是其类型所需的对齐倍数。
  • 对齐规则:
    1. 每个成员的起始地址必须是其自身类型对齐要求的倍数。
    2. 结构体的总大小必须是最大对齐要求的倍数。

计算结构体的字节数:

> 结构体最终的字节数一定是 对齐字节数的 整数倍
> 在32操作系统中,最大4字节对齐
> 在64操作系统中,最大8字节对齐
> 取 结构体中 最大的 那个成员基本组成类型字节数 作为 对齐字节数 
> 每个成员的起始位置到结构体的起始位置之间的字节数 是 该成员 基本组成 字节数的 整数倍 

影响结构体大小的因素:

  • 成员类型的对齐
    • 不同数据类型的对齐要求可能不同(通常与数据类型的大小一致)。
    • 示例(32位系统):
      • char:1字节对齐。
      • short:2字节对齐。
      • int、float:4字节对齐。
      • double:8字节对齐。
  • 编译器的填充(Padding)
    • 为了满足对齐要求,结构体成员之间可能会插入填充字节(Padding)。
    • 结构体的总大小也会填充到最大对齐要求的倍数。
  • 最大对齐要求
    • 结构体总大小必须是其最大成员对齐要求的倍数。

内存布局详情:

struct xx
{
    long long ll;
    char c;
    int *p;
    char name[21];
    short s;
    double d;
    float f;
    short x;
};

64位系统下结构体的字节数
32位系统下的结构体
32位系统下的结构体字节数

也可以人为设定对齐字节数

在32操作系统中,最大4字节对齐
在64操作系统中,最大8字节对齐

#pragma pack(n)     n: 是2的幂次方  2^0   2^1 2^2  2^3 

代码示例:
1:无填充字节

#include <stdio.h>

struct S1 {
    char a;      // 1字节
    int b;       // 4字节
};

int main() {
    printf("Size of S1: %lu\n", sizeof(struct S1));
    return 0;
}

内存布局:

+---+---+---+---+
| a | P | P | P |  // char a (1字节) + 3字节填充
+---+---+---+---+
|       b       |  // int b (4字节)
+---+---+---+---+
  • char a 占 1 字节,但 int b 需要 4 字节对齐,因此插入 3 字节填充。
  • 总大小为 8 字节。
Size of S1: 8

2:多个对齐要求

#include <stdio.h>

struct S2 {
    char a;      // 1字节
    double b;    // 8字节
    int c;       // 4字节
};

int main() {
    printf("Size of S2: %lu\n", sizeof(struct S2));
    return 0;
}

内存布局:

+---+---+---+---+---+---+---+---+
| a | P | P | P | P | P | P | P |  // char a + 7字节填充
+---+---+---+---+---+---+---+---+
|           b                   |  // double b (8字节)
+---+---+---+---+---+---+---+---+
|       c       |   P   |   P   |  // int c (4字节) + 4字节填充
+---+---+---+---+---+---+---+---+
  • char a 占 1 字节,double b 需要 8 字节对齐,因此插入 7 字节填充。
  • int c 需要 4 字节对齐,但结构体总大小需为 8 的倍数,因此插入 4 字节填充。
  • 总大小为 24 字节。
Size of S2: 24

3:改变成员顺序减少填充
调整示例 2 的成员顺序:

struct S3 {
    double b;    // 8字节
    int c;       // 4字节
    char a;      // 1字节
};

内存布局:

+---+---+---+---+---+---+---+---+
|           b                   |  // double b (8字节)
+---+---+---+---+---+---+---+---+
|       c       |   a   |   P   |  // int c + char a + 3字节填充
+---+---+---+---+---+---+---+---+
  • 调整成员顺序后,总大小为 16 字节,减少了填充字节。

输出:

Size of S3: 16

4. 结构体嵌套的字节大小
嵌套结构体会继承成员的对齐规则,可能导致额外的填充字节。(此处仅做简单介绍,详细分析请跳转至 结构体嵌套 文章,对结构体的嵌套有详细说明)

代码

#include <stdio.h>

struct Inner {
    char a;      // 1字节
    int b;       // 4字节
};

struct Outer {
    char c;      // 1字节
    struct Inner inner;  // 8字节(受对齐规则影响)
    double d;    // 8字节
};

int main() {
    printf("Size of Inner: %lu\n", sizeof(struct Inner));
    printf("Size of Outer: %lu\n", sizeof(struct Outer));
    return 0;
}

内存布局:

Inner:
+---+---+---+---+---+
| a | P |   b       |
+---+---+---+---+---+

Outer:
+---+---+---+---+---+---+---+---+
| c | P |   Inner (8字节)       |
+---+---+---+---+---+---+---+---+
|               d               |
+---+---+---+---+---+---+---+---+
Inner 的大小为 8 字节(对齐到 4 的倍数)。
Outer 的最大对齐要求是 double d 的 8 字节,总大小为 24 字节。

输出:

Size of Inner: 8
Size of Outer: 24

联合体(union)

联合体的定义:
  • 联合体的所有成员共享同一块内存空间。
  • 联合体的大小取决于其最大成员的大小。
  • 联合体的对齐要求由最大成员的对齐要求决定。

语法:

union [标签] {
	成员属性;
	成员属性;
	成员属性;
	成员属性;
};

定义:

union {
	int a;
	short b;
	char c;
}   // 联合体 类型 

typedef union {int a; short b; char c;} xx_t;//取别名
xx_t y;

union qq{int a; short b; char c;}  // 有了新的联合体类型,并创建了新的标签
union qq xq; 

赋值:

typedef union {int a; short b; char c;} xx_t;
xx_t y;

y.a = 10; //同结构体一样
(&y)->b = 20;

联合体的存储(字节数如何计算):

  • 占用空间最大的成员字节数作为基础字节数。
  • 最终的字节数一定是 每个成员基本组成类型字节数的整数倍。
union xx
{
    char name[20];
    long long ll;
    double d;
    int *p;
    short s;
};

示例代码中联合体的大小取决于其最大成员 char name[20];,所以大小为20字节。
联合体占用的字节大小
代码:
1:简单联合体

#include <stdio.h>

union U1 {
    char a;      // 1字节
    int b;       // 4字节
    double c;    // 8字节
};

int main() {
    printf("Size of U1: %lu\n", sizeof(union U1));
    return 0;
}
+---+---+---+---+---+---+---+---+
|               c               |  // double c (8字节)
+---+---+---+---+---+---+---+---+
  • 这个联合体的大小取决于其最大成员 double c,所以大小为 8 字节。

输出:

Size of U1: 8

2:联合体的对齐

#include <stdio.h>

union U2 {
    char a;      // 1字节
    int b;       // 4字节
    short c;     // 2字节
};

int main() {
    printf("Size of U2: %lu\n", sizeof(union U2));
    return 0;
}

内存布局:

+---+---+---+---+
|       b       |  // int b (4字节)
+---+---+---+---+
  • 联合体的最大成员是 int b(4 字节),所以联合体的大小为 4 字节。

输出:

Size of U2: 4

枚举类型(enum)

定义:枚举类型(enum)是C语言中定义一组命名整型常量的方法,用于表示一组离散的、有意义的值。 它是C语言的基本类型之一,主要用于提高代码的可读性和可维护性。

定义有些抽象,不太易于理解,用大白话翻译一下就是:① 结构体是把不同的成员捆绑在一起,形成一个新的类型,方便于面向对象编程,适用于实例化对象使用。② 联合体也是创建一个新的类型,只不过它的成员是共用一块空间,而结构体成员是分别使用空间。③ 枚举类型则是用于限制取值范围的。

语法:

enum [标签] {
	枚举常量,
	枚举常量,
	枚举常量,
	枚举常量,
	枚举常量
};
  • 枚举常量: 枚举常量是int型的常量,在使用int类型的任何地方都可以使用它。
  • 默认值: 没有特定指出常量值时,枚举列表中的常量被指定为整数值0、1、2等,依次递增。
  • 指定值: 可以选择常量具有的整数值,后面的常量会被赋予后续的值。

定义:

enum {XX,YY,ZZ,QQ,TT}  // 4个字节 

enum {XX,YY,ZZ,QQ,TT} xy = XX;

typedef  enum {XX,YY,ZZ,QQ,TT} hh_t;

带标签:
enum Weekday {MON, TUE, WEN, THU, FRI,SAT, SUN};
MON : 0  ---> 依次往后加1 //枚举常量的值 下面的代码块中会进一步详细说明

enum Weekday {MON=10,TUE, WEN, THU=100, FRI,SAT, SUN};  //这个类型 4个字节 
enum Weekday yy =  WEN;//赋值:只能在枚举类型中限定的范围内查找

//枚举和 typedef:通过 typedef 为枚举类型定义别名,简化代码
typedef enum Weekday {MON=10,TUE, WEN, THU=100, FRI,SAT, SUN} week_t;

void fun(week_t xx)
{
     
}
fun(MON);//从此之后,此函数中的传值被限制了范围,只能在 enum Weekday中查找。

写一个示例代码,详细讲述一下枚举类型的使用场景:

enum 枚举类型名 {
    枚举常量1,
    枚举常量2,
    枚举常量3,
    ...
};
  • enum:枚举类型的关键字。
  • 枚举类型名/[标签]:可选,表示该枚举的类型名称。
  • 枚举常量:一组用逗号分隔的命名常量,默认从 0 开始递增(可以手动指定值)。

使用:

#include <stdio.h>

// 定义枚举类型
enum Color {
    RED,    // 默认值 0
    GREEN,  // 默认值 1
    BLUE    // 默认值 2
};

int main() {
    enum Color myColor;  // 声明枚举变量

    myColor = GREEN;     // 给枚举变量赋值
    printf("My color is: %d\n", myColor);  // 输出枚举变量的值

    return 0;
}

输出:

My color is: 1

枚举常量的值

默认值

  • 枚举常量的值从 0 开始,依次递增。
  • 如果手动为某个枚举常量指定值,则后续常量的值在此基础上递增。

手动指定值

#include <stdio.h>

// 定义枚举类型,并手动指定值
enum Weekday {
    MONDAY = 1,    // 指定为 1
    TUESDAY,       // 自动递增为 2
    WEDNESDAY = 5, // 指定为 5
    THURSDAY,      // 自动递增为 6
    FRIDAY         // 自动递增为 7
};

int main() {
    printf("MONDAY = %d\n", MONDAY);
    printf("TUESDAY = %d\n", TUESDAY);
    printf("WEDNESDAY = %d\n", WEDNESDAY);
    printf("THURSDAY = %d\n", THURSDAY);
    printf("FRIDAY = %d\n", FRIDAY);

    return 0;
}

输出:

MONDAY = 1
TUESDAY = 2
WEDNESDAY = 5
THURSDAY = 6
FRIDAY = 7

枚举值的重复: 枚举常量可以有重复的值。

enum Example {
    A = 1,
    B = 1,  // B 和 A 的值相同
    C = 2
};

匿名枚举
  • 如果不需要为枚举类型定义名字,可以使用匿名枚举。
  • 枚举常量会成为全局常量,直接使用。

代码

#include <stdio.h>

enum {
    SUCCESS = 0,
    FAILURE = -1
};

int main() {
    printf("SUCCESS = %d\n", SUCCESS);
    printf("FAILURE = %d\n", FAILURE);

    return 0;
}

输出:

SUCCESS = 0
FAILURE = -1

枚举类型的大小
  • 枚举变量的本质:
    • 枚举类型在底层是一个整数类型,通常是 int(具体大小取决于编译器)。
  • 内存大小:
    • 一个枚举变量的大小与 int 相同(4字节或8字节,取决于平台)。

代码

#include <stdio.h>

enum Example {
    A = 1,
    B,
    C
};

int main() {
    printf("Size of enum: %lu bytes\n", sizeof(enum Example));
    return 0;
}

输出(在 64 位系统上):

Size of enum: 4 bytes
枚举类型的限制和注意事项

枚举变量的类型:

  • 枚举类型的底层是整型,因此可以与整数进行比较或赋值。
  • 但这种用法可能会降低代码的可读性。

代码说明

#include <stdio.h>

enum Color {
    RED,
    GREEN,
    BLUE
};

int main() {
    enum Color myColor;

    myColor = 1;  // 虽然可以赋值为整数,但不推荐
    printf("My color is: %d\n", myColor);

    return 0;
}

输出:

My color is: 1
//注意:虽然语法上允许,但这样会破坏枚举的意义。建议始终使用枚举常量赋值。

枚举类型的范围: 枚举常量的值不能超过整型的表示范围,其本质是个 int 常量。如果枚举值太大,可能会导致编译器警告或错误。
枚举和类型安全: C语言中的枚举并不强制类型安全。枚举变量可以被赋值为任何整数值,编译器不会报错。


枚举类型的作用
  1. 提高可读性:枚举类型使用有意义的命名代替魔法数字(Magic Numbers)。例如,使用 RED 代替数字 0,提高代码可读性。
  2. 提高可维护性:如果枚举的值发生变化,只需修改枚举定义,而不用修改其他代码。
  3. 限制变量取值范围:枚举变量只能取定义的枚举常量值,避免了非法值的使用。
枚举的高级用法

最后举 2 种枚举类型在编程中的常用场景:
1. 枚举结合 switch 语句使用: 枚举常常与 switch 语句结合使用,方便处理多个分支逻辑。

代码片:

#include <stdio.h>

enum State {
    OFF,
    ON,
    SUSPEND
};

int main() {
    enum State deviceState = ON;

    switch (deviceState) {
        case OFF:
            printf("Device is OFF.\n");
            break;
        case ON:
            printf("Device is ON.\n");
            break;
        case SUSPEND:
            printf("Device is in SUSPEND mode.\n");
            break;
        default:
            printf("Unknown state.\n");
    }

    return 0;
}

输出:

Device is ON.

2. 枚举用于位标志: 枚举可以用于定义位标志,方便对多个状态进行位操作。

代码片:

#include <stdio.h>

enum Permission {
    READ = 1 << 0,  // 0001
    WRITE = 1 << 1, // 0010
    EXECUTE = 1 << 2 // 0100
};

int main() {
    int permission = READ | WRITE;  // 组合权限

    if (permission & READ) {
        printf("Read permission is granted.\n");
    }
    if (permission & WRITE) {
        printf("Write permission is granted.\n");
    }
    if (permission & EXECUTE) {
        printf("Execute permission is granted.\n");
    }

    return 0;
}

输出:

Read permission is granted.
Write permission is granted.

综上。需要简单记住的是:
1. 结构体大小计算规则

  1. 每个成员按其对齐要求分配地址。
  2. 结构体总大小对齐到最大对齐要求的倍数。
  3. 填充(Padding)字节会增加结构体大小。

2 联合体大小计算规则

  1. 联合体的大小由最大成员的大小决定。
  2. 联合体的对齐要求由最大成员的对齐要求决定。

3. 枚举类型大小计算规则

  1. 枚举类型在底层是一个整数类型,通常是 int(具体大小取决于编译器)。
  2. 内存大小:一个枚举变量的大小与 int 相同(4字节或8字节,取决于平台)。

可优化建议

  1. 调整成员顺序:将对齐要求高的成员放在前面,减少填充字节。
  2. 使用 #pragma pack:可以改变默认对齐方式,但可能影响性能。
  3. 注意嵌套结构体的对齐:嵌套结构体的总大小也需满足对齐规则。

通过理解这些规则,可以优化结构体和联合体的内存布局,从而提高程序的性能和内存利用率。

此篇文章仅仅只是对结构体、联合体、枚举类型的基础教育,简单讲解了它们是如何占用内存空间大小的,下一篇文章中会更进一步的讲解说明;
其中包含:结构体嵌套以及实际开发中的使用,位域、无名位域和空域详解并包含嵌入式开发工作中实际场景说明。链接:位域、无名位域和空域详解

以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

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

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

相关文章

免交互运用

免交互的概念 文本免交互 免交互的格式 变量配置 expect expect的格式 在脚本外传参 嵌套 练习 免交互ssh远程连接

物联网客户端在线服务中心(客服功能/私聊/群聊/下发指令等功能)

一、界面 私聊功能&#xff08;下发通知类&#xff0c;一对多&#xff09;群聊&#xff08;点对点&#xff09;发送指令&#xff08;配合使用客户端&#xff0c;基于cefsharp做的物联网浏览器客户端&#xff09;修改远程参数配置&#xff08;直接保存到本地&#xff09;&#…

使用C#开发VTK笔记(一)-开发环境搭建

一.使用C#开发VTK的背景 因为C#开发的友好性,一直都比较习惯于从C#开发程序。而长期以来,都希望有一个稳定可靠的三位工程数模的开发演示平台,经过多次对比之后,感觉VTK和OpenCasCade这两个开源项目是比较好的,但它们都是用C++编写的,我用C#形式开发,只能找到发布的C#组…

力扣96:不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;1 卡…

k8s Init:ImagePullBackOff 的解决方法

kubectl describe po (pod名字) -n kube-system 可查看pod所在的节点信息 例如&#xff1a; kubectl describe po calico-node-2lcxx -n kube-system 执行拉取前先把用到的节点的源换了 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"re…

人工智能如何改变你的生活?

在我们所处的这个快节奏的世界里&#xff0c;科技融入日常生活已然成为司空见惯的事&#xff0c;并且切实成为了我们生活的一部分。在这场科技变革中&#xff0c;最具变革性的角色之一便是人工智能&#xff08;AI&#xff09;。从我们清晨醒来直至夜晚入睡&#xff0c;人工智能…

道路机器人识别交通灯,马路,左右转,黄线,人行道,机器人等路面导航标志识别-使用YOLO标记

数据集分割 train组66% 268图片 validation集22% 91图片 test集12&#xff05; 48图片 预处理 没有采用任何预处理步骤。 增强 未应用任何增强。 数据集图片&#xff1a; 交通灯 马路 右转 向右掉头 机器人识别 人行横道 黄线 直行或右转 数据集下载&#xff1a; 道路…

【四轴】利用PWM捕获解析接收机信号

在学习这部分之间&#xff0c;建议大家先看之前这篇博客&#xff0c;里面包含对PWM一些重要概念的基本介绍。 【四轴】利用PWM输出驱动无刷电机-CSDN博客 1. 基本原理 1.1 PWM是什么 这一部分可以看我之前的博客&#xff0c;已经对PWM有了基本的介绍。 1.2 什么叫捕获PWM波&…

洛谷 P1162 填涂颜色 C语言 bfs

题目&#xff1a; https://www.luogu.com.cn/problem/P1162 由数字 0 组成的方阵中&#xff0c;有一任意形状的由数字 1 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如&#xff1a;66的方阵&#xff08;n6&#xff09;&#xff0c;涂色前和涂色后的方阵如下&am…

38 基于单片机的宠物喂食(ESP8266、红外、电机)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;采用L298N驱动连接P2.3和P2.4口进行电机驱动&#xff0c; 然后串口连接P3.0和P3.1模拟ESP8266&#xff0c; 红外传感器连接ADC0832数模转换器连接单片机的P1.0~P1.…

霍夫变换:原理剖析与 OpenCV 应用实例

简介&#xff1a;本文围绕霍夫变换相关内容展开&#xff0c;先是讲解霍夫变换基本原理&#xff0c;包含从 xy 坐标系到 kb 坐标系及极坐标系的映射等。接着介绍了 cv2.HoughLines、cv2.HoughLinesP 概率霍夫变换、cv2.HoughCircles 霍夫圆变换的函数用法、参数含义、与常规霍夫…

【Debug】hexo-github令牌认证 Support for password authentication was removed

title: 【Debug】hexo-github令牌认证 date: 2024-07-19 14:40:54 categories: bug解决日记 description: “Support for password authentication was removed on August 13, 2021.” cover: https://pic.imgdb.cn/item/669b38ebd9c307b7e9f3e5e0.jpg 第一章 第一篇博客记录一…

JVM 性能调优 -- JVM常用调优工具【jps、jstack、jmap、jstats 命令】

前言&#xff1a; 前面我们分析怎么去预估系统资源&#xff0c;怎么去设置 JVM 参数以及怎么去看 GC 日志&#xff0c;本篇我们分享一些常用的 JVM 调优工具&#xff0c;我们在进行 JVM 调优的时候&#xff0c;通常需要借助一些工具来对系统的进行相关分析&#xff0c;从而确定…

net9 abp vnext 多语言通过数据库动态管理

通过数据库加载实现动态管理&#xff0c;用户可以自己修改界面显示的文本&#xff0c;满足国际化需求 如图所示,前端使用tdesign vnext 新建表TSYS_Localization与TSYS_LocalizationDetail 国旗图标下载网址flag-icons: Free Country Flags in SVG 在Shared下创建下图3个文件 …

Vue:使用 KeepAlive 缓存切换掉的 component

一、内置特殊元素 不是组件 <component>、<slot> 和 <template> 具有类似组件的特性&#xff0c;也是模板语法的一部分。但它们并非真正的组件&#xff0c;同时在模板编译期间会被编译掉。因此&#xff0c;它们通常在模板中用小写字母书写。 1.1 <compone…

Spring中每次访问数据库都要创建SqlSession吗?

一、SqlSession是什么二、源码分析1&#xff09;mybatis获取Mapper流程2&#xff09;Spring创建Mapper接口的代理对象流程3&#xff09;MapperFactoryBean#getObject调用时机4&#xff09;SqlSessionTemplate创建流程5&#xff09;SqlSessionInterceptor拦截逻辑6&#xff09;开…

【数据结构】填空集

基本术语 顺序队列在实现的时候&#xff0c;通常将数组看成是一个首尾相连的循环队列&#xff0c;这样做的目的是为避免产生&#xff08;溢出&#xff09;现象 数组q[M]&#xff08;M等于6&#xff09;存储一个循环队&#xff0c;first和last分别指向首尾指针。已知first2,la…

【趣味升级版】斗破苍穹修炼文字游戏HTML,CSS,JS

目录 图片展示 开始游戏 手动升级&#xff08;满100%即可升级&#xff09; 升级完成&#xff0c;即可解锁打怪模式 新增功能说明&#xff1a; 如何操作&#xff1a; 完整代码 实现一个简单的斗破苍穹修炼文字游戏&#xff0c;你可以使用HTML、CSS和JavaScript结合来构建…

【在Linux世界中追寻伟大的One Piece】多线程(三)

目录 1 -> Linux线程同步 1.1 -> 条件变量 1.2 -> 同步概念与竞态条件 1.3 -> 条件变量函数 1.4 -> 为什么pthread_cond_wait需要互斥量 1.5 -> 条件变量使用规范 2 -> 生产者消费者模型 2.1 -> 为什么要使用生产者消费者模型 2.2 -> 生产…

AI数据分析工具(一)

Looker Studio&#xff08;谷歌&#xff09;-免费 优点 免费使用&#xff1a;对于中小型企业和个人用户来说&#xff0c;没有任何费用压力&#xff0c;可以免费享受到数据可视化和报表创建的功能。与Google服务集成&#xff1a;特别适合使用Google产品生态的企业&#xff0c;…