<C语言> 自定义类型

news2024/12/29 14:46:07

1.结构体

结构体是一种用户自定义的数据类型,允许将不同类型的数据项组合在一起,形成一个更大的数据结构。结构体可以包含多个成员变量,每个成员变量可以是不同的数据类型,如整数、字符、浮点数等,甚至可以包含其他结构体作为其成员。

复杂对象人:名字+年龄+电话+住址

结构体struct-描述复杂对象

1.1 结构体的声明

struct tag
{
 	member-list;
}variable-list;
  1. struct是关键字,用于声明一个结构体类型。tag是给这个结构体类型起的标识符,用于在后续代码中引用这个结构体类型。
  2. member-list表示结构体的成员列表,每个成员用一个数据类型和标识符定义。这些成员在结构体内部依次存储。
  3. variable-list 这个部分不是结构体的必须组成部分,但是可以用来在定义结构体的同时创建结构体变量。如果在定义结构体时不创建变量,可以忽略这部分。

例如描述一个人:

#include <stdio.h>

// 定义结构体类型
struct Person {
    char name[50];
    int age;
    float height;
} person1, person2; // 创建两个结构体变量 person1 和 person2,注意分号不可以缺少

int main() {
    // 初始化结构体变量
    struct Person person3 = {"John Doe", 30, 1.75};
    
    // 访问结构体成员
    printf("Name: %s\n", person3.name);
    printf("Age: %d\n", person3.age);
    printf("Height: %.2f meters\n", person3.height);
    
    return 0;
}

1.2 匿名结构体

匿名结构体是指在定义结构体变量时,省略结构体的名称,直接声明结构体变量并定义其成员。这种形式适用于一些临时或简单的数据组织需求,不需要为结构体类型起一个独立的名字。匿名结构体的作用范围仅限于当前代码块。

例如:

#include <stdio.h>

int main() {
    // 定义匿名结构体变量,并直接初始化
    struct {
        float length;
        float width;
    } rectangle = {5.0, 3.0}; // 创建结构体变量并初始化
    
    // 计算矩形的面积
    float area = rectangle.length * rectangle.width;
    
    printf("Rectangle Length: %.2f\n", rectangle.length);
    printf("Rectangle Width: %.2f\n", rectangle.width);
    printf("Rectangle Area: %.2f\n", area);
    
    return 0;
}

问题,下面的代码合法吗?

struct
{
    char book_name[20];
    char author[20];
    int price;
    char id[15];
} sb1, sb2;

struct
{
    char book_name[20];
    char author[20];
    int price;
    char id[15];
} *ps;

int main() {
    ps=&sb1;  //err,编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。
    return 0;
}

警告: 编译器会把上面的两个声明当成完全不同的两个类型。 所以是非法的。

总结:

匿名结构体适用于一些临时的数据组织,特别是在某个作用域内部且仅在局部范围使用的情况下,这样可以省略给结构体起一个名称的步骤,使得代码更加简洁和清晰。然而,对于需要在多个函数或多个地方使用的复杂数据结构,还是推荐使用带有名称的结构体类型。

1.3 结构体的自引用

结构体的自引用指的是结构体中包含指向相同类型结构体的指针成员,从而创建一个自循环的数据结构

链表结构就要利用结构体的自引用来实现:

typedef struct Node { //对struct Node重命名为Node
    int data;
    struct Node *next; //指向下个结点的地址,这里的struct不能省略
} Node;

int main() {
    Node n;
    return 0;
}

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

struct Point{
    int x;
    int y;
} p1;            //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2

//初始化:定义变量的同时赋初值。
struct Point p3 = {1, 2};

struct Stu {       //类型声明
    char name[15]; //名字
    int age;       //年龄
};
struct Stu s = {"zhangsan", 20}; //初始化

结构体还可以嵌套初始化:

struct Node {
    int data;
    struct Point p;                 //4,5
    struct Node *next;              //NULL
} n1 = {10, {4, 5}, NULL};          //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化 

不按顺序初始化:

struct S {
    char c;
    int a;
    float f;
};

int main() {
    struct S s = {'w', 20, 3.14f};      //顺序初始化
    printf("%c %d %f\n", s.c, s.a, s.f);
    struct S s2 = {s2.f = 3.14f, s2.c = 'w', s2.a = 10};   //不按顺序初始化
    printf("%c %d %f\n", s.c, s.a, s.f);
    return 0;
}

注意:不按顺序初始化,VS可以 gcc编译器不支持

1.5 结构体成员的访问

可以使用点操作符(.)来访问结构体的成员。点操作符允许我们通过结构体变量来访问结构体内部的成员变量,使得我们可以读取或修改这些成员的值。如果结构体是指针类型,我们可以使用箭头操作符(->)来访问指向的内容。

例如以下结构体成员:

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

struct Stu s;

我们可以看到 s 有成员 nameage

那我们如何访问s的成员?

struct S s;
strcpy(s.name, "zhangsan");//使用.访问name成员
s.age = 20;//使用.访问age成员

结构体指针访问指向变量的成员

有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。

那该如何访问成员

如下:

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

void print(struct Stu *ps) {
    printf("name = %s   age = %d\n", (*ps).name, (*ps).age);
    //使用结构体指针访问指向对象的成员
    printf("name = %s   age = %d\n", ps->name, ps->age);
}

int main() {
    struct Stu s = {"zhangsan", 20};
    print(&s);//结构体地址传参
    return 0;
}

使用(*ps)解引用后.操作访问,或者->直接访问

1.6 结构体传参

结构体可以按值传递或按指针传递给函数。在按值传递时,函数将接收到结构体的副本,对副本的修改不会影响原始结构体。在按指针传递时,函数将接收到结构体的地址,可以直接修改原始结构体的内容。

例如:

struct S {
    int data[1000];
    int num;
};

void print1(struct S s) {
    //传值比较浪费空间,可能会栈溢出
    printf("%d %d %d %d\n", s.data[0], s.data[1], s.data[2], s.num);// 1 2 3 100
}

void print2(struct S *ps) {
    //两种写法  推荐第二个
    printf("%d %d %d %d\n", (*ps).data[0], (*ps).data[1], (*ps).data[2], (*ps).num);// 1 2 3 100
    printf("%d %d %d %d\n", ps->data[0], ps->data[1], ps->data[2], ps->num);        // 1 2 3 100
}

int main() {
    struct S ss = {{1, 2, 3, 4, 5}, 100};
    print1(ss);
    print2(&ss);
    return 0;
}

上面的 print1print2 函数哪个好些?

答案是:首选print2函数。

原因:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的 下降。

1.7 结构体内存对齐

结构体的内存对齐是编译器根据特定的规则将结构体成员按照一定的字节边界进行排列的过程。对齐的目的是为了优化内存访问效率,避免因为数据未对齐而导致的性能损失。对齐原则因编译器和体系结构而异

如何计算?

首先得掌握结构体的对齐规则:

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

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

对齐数 = 编译器默认的一个对齐数与该成员大小的较小值VS中默认的值为8

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

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

观察下面的结果:

#include <stddef.h>
#include <stdio.h>
struct S1 {
    char c1;
    int i;
    char c2;
};

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

int main() {
    //S1的偏移量
    printf("%d\n", offsetof(struct S1, c1));//0  c1从0开始
    printf("%d\n", offsetof(struct S1, i)); //4	 i从4开始
    printf("%d\n", offsetof(struct S1, c2));//8  c2从8开始 8+1字节=9字节,按4字节对齐=12
    
    printf("%d\n", offsetof(struct S2, c1));//0  c1从0开始
    printf("%d\n", offsetof(struct S2, c2));//1  c2从1开始  
    printf("%d\n", offsetof(struct S2, i)); //4  i从4开始  4+4=8字节,按4字节对齐=8

    printf("%d\n",sizeof(struct S1)); //12
    printf("%d\n",sizeof(struct S2)); //8
    return 0;
}

offsetof宏-用来计算结构体成员相对于起始位置的偏移量,头文件#include

练习:

struct S3 {
    double d;// 0 - 7
    char c;  // 8
    int i;   // 12-15
};

struct S4 {
    char c1;     // 0
    struct S3 s3;// 8-20   s3
    double d;    // 24-31
};

int main() {
    printf("%d\n", sizeof(struct S3));// 16
    printf("%d\n", sizeof(struct S4));// 32
    return 0;
}

首先,我们有两个结构体 struct S3struct S4

struct S3 中包含了三个成员:

  1. double d:占用8个字节(通常情况下是64位浮点数的大小)。
  2. char c:占用1个字节。
  3. int i:占用4个字节。

由于结构体中的成员变量的对齐数通常是成员本身大小和编译器默认对齐数(在Visual Studio中默认是8字节)中较小的值,所以每个成员都需要对齐到8字节的整数倍地址处。

所以 struct S3 的总大小是 8 + 1 + 4 = 13 字节。但由于对齐的需要,结构体的总大小会被调整为最大对齐数的整数倍,所以 sizeof(struct S3) 的结果为 16 字节。

接下来,我们看 struct S4

struct S4 中包含了两个成员:

  1. char c1:占用1个字节。
  2. struct S3 s3:占用 sizeof(struct S3) = 16 字节。

struct S4 中,由于 struct S3 s3 的是16字节,编译器默认对齐数是8字节,所以 double d 需要对齐到8字节的整数倍地址处。因此,在 struct S4 中,double d 的偏移量为 24 字节。

总字节大小为32字节,是8的对齐数,所以结果就是8字节

为什么存在内存对齐?

  • 平台原因(移植原因):

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

  • 2.性能原因:

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

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的成员尽量集中在一起。

//例如:
struct S1 {
    char c1;
    int i;
    char c2;
};

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

S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。

1.8 修改默认对齐数

可以通过预处理指令来修改结构体的默认对齐数。在大多数编译器中,可以使用#pragma pack指令来实现这一点。

#pragma pack 指令允许你指定对齐数的大小,从而改变结构体成员在内存中的对齐方式。通常情况下,对齐数是编译器默认的一个值和该成员大小的较小值,但通过#pragma pack,你可以设置一个不同的对齐数。

例如,假设将默认对齐数设置为4字节,可以这样做:

#pragma pack(4)

struct YourStruct {
    // 结构体成员
};

#pragma pack() // 重置为默认对齐数

注意,修改对齐数可能会影响结构体的内存布局和性能。通常情况下,编译器的默认对齐数是为了在不同平台上实现最佳的内存对齐和访问效率。如果不是很确定需要修改对齐数,最好还是使用编译器的默认设置。

如果需要修改对齐数,建议只在必要时进行,并且要确保所有的相关代码都知道这个修改,以免引起不必要的问题。在修改对齐数时,最好先了解你的编译器支持的具体语法和特性,以便正确地使用#pragma pack指令。

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
//8和成员大小最小-对齐数4
struct S1 {
    char c1;   //0
    int i;     //4
    char c2;   //9    对齐4为12
};

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

//对齐数为1,成员大小为4,对齐数为1
struct S2 {
    char c1;   //0
    int i;     //1
    char c2;   //5      对齐数为1表示不对齐,大小为0到5=6
};

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

int main() {
    //输出的结果是什么?
    printf("%d\n", sizeof(struct S1));  //12
    printf("%d\n", sizeof(struct S2));  //6
    return 0;
}

2.结构体位段

结构体位段是一种特殊的结构体成员,允许你以位为单位定义成员的长度。它们用于有效地使用内存,特别是在需要处理硬件寄存器或二进制数据的情况下。结构体位段可以在结构体声明中指定成员的位宽,从而使得这些成员只占用特定数量的位而不是整个字节。

位段的声明和结构是类似的,有两个不同:

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

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

比如:

struct S {
    int a;
    int b;
    int c;
    int d;
};

//A是位段-其中的位其实是二进制位
struct A {
    //先开辟了4byte - 32bit
    int _a : 2; // a成员只需要2个比特位  32-2 = 30
    int _b : 5; // b成员只需要5个比特位  30-5 = 25
    int _c : 10;// c成员只需要10个比特位 25-10 = 15    剩余的15个字节怎么使用由编译器决定
    int _d : 30;// d成员只需要30个比特位  还剩15 不够用 又开辟了四个字节的空间  一共8个字节
};

int main() {
    printf("%d\n", sizeof(struct S));// 16
    printf("%d\n", sizeof(struct A));// 8
    return 0;
}

2.1 位段的内存分配

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

一个例子:

struct S
{
    char a : 3;  //一个字节8个比特  8-3 = 5 还有五个比特
    char b : 4;  //5-4  还剩1个比特  再开辟一个字节空间
    char c : 5;  //5  //还剩下3个比特  又开辟一个空间
    char d : 4;  //4
};

int main()
{
    printf("%d\n", sizeof(struct S)); // 3
    struct S s = {0};
    s.a = 10;  //10的二进制 1010  但是a位段位3   只能放三位  00000010
    s.b = 12;  //1100  1字节变成01100010 = 十六进制62
    s.c = 3;   //0011    00000011 - 03
    s.d = 4;   //0100    00000100 - 04
    //内存中对应62 03 04 
    return 0;
} 

在这里插入图片描述

2.2 位段的跨平台问题

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

总结:

跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

3.枚举

枚举(Enum)是一种用户定义的数据类型,用于表示一组具名的整数常量。枚举允许程序员为不同的值指定有意义的名字,使得代码更加清晰和易读。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。

性别有:男、女、保密,也可以一一列举。

月份有12个月,也可以一一列举

3.1 枚举类型的定义

语法如下:

enum enumName {
    value1,
    value2,
    value3,
    // more values...
};

在枚举中,enumName 是枚举类型的名称,value1, value2, value3, … 是枚举常量。每个常量都隐式地被赋予一个整数值,其值默认从0开始递增。当然在定义的时候也可以赋初值。

例如:

enum Color//颜色
{
    RED = 1,
    GREEN = 2,
    BLUE = 4
};

枚举类型的大小?

枚举类型在C语言中的大小取决于编译器的实现和平台的架构。虽然C标准没有规定具体的枚举类型大小,但大多数编译器将枚举实现为整数类型(通常是intunsigned int),以便能够容纳枚举中定义的所有常量值。

通常情况下,枚举类型的大小是整数类型的大小,即通常为4个字节(32位平台)或8个字节(64位平台)。

3.2 枚举类型的优点

为什么使用枚举?

我们可以使用 #define 定义常量,为什么非要使用枚举?

#define Red 5
#define Green 7
#define Blue 10
int main(){
	int num = Red;
	return 0;
}

define预处理后define命令就消失了替换成了数字 ,不方便调试

枚举的优点:

1.增加代码的可读性和可维护性

2.和#define定义的标识符比较枚举有类型检查,更加严谨

3.便于调试

4.使用方便,一次可以定义多个常量

5.防止命名污染(封装)

3.3 枚举的使用

enum Color {
    //枚举的可能取值
    //每一个可能的取值是常量
    Red,
    Green,
    Blue
    //Red = 5
    //Red = 9
    //Red = 10
};

int main() { 
    enum Color color = Blue;   //只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
    //enum Color color = 5;    //C语言支持, C++会有警告
    //Red = 2;   //常量不可修改
    int num = Red;
    printf("%d\n", num);               //0
    printf("%d\n", Red);               //0
    printf("%d\n", Green);             //1
    printf("%d\n", Blue);              //2
    int sum = Red + Blue;              //可以相加,但是有些编译器不支持
    printf("%d\n", sum);               //2
    printf("%d\n", sizeof(enum Color));//VS中为4
    
    return 0;
}

注意:枚举常量不可修改

4.联合体(共用体)

联合体(Union)是一种特殊的数据类型,允许在同一块内存空间中存储不同类型的数据。与结构体不同,联合体的成员共享同一块内存,但每次只有一个成员是有效的。联合体的大小取决于其成员中最大的成员大小。

定义联合体的语法如下:

union unionName {
    memberType member1;
    memberType member2;
    // more members...
};

在联合体中,unionName 是联合体类型的名称,member1, member2, … 是联合体的成员。每个成员都可以是不同的数据类型,但它们共享相同的内存空间。

4.1 联合体的特点

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

实例如下:

#include <stdio.h>
union Un {
    char c;
    int i;
    double d;
};


int main() {
    union Un un;
    printf("%p\n", &un);    //000000000061FE18
    printf("%p\n", &(un.c));//000000000061FE18
    printf("%p\n", &(un.i));//000000000061FE18
    printf("%p\n", &(un.d));//000000000061FE18
    //地址相同
    printf("%d\n", sizeof(union Un));//8个字节
    return 0;
}

下面输出的结果是什么?

un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i); 

结果:11223355

在这个代码中,首先将0x11223344赋给了un.i,这将整数的所有4个字节设置为十六进制的11 22 33 44。然后,将0x55赋给了un.c,这只会将整数的第一个字节设置为十六进制的55。由于整数的第一个字节先前已设置为11,因此在赋值后它变为了55。因此,当打印出un.i的值时,它将等于十六进制的11223355

4.2 联合体大小计算

  • 联合体的大小取决于它包含的成员中最大的数据类型的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

比如:

union Un {
    char arr[5];//5 对齐数为1
    int i;      //4
};

union Un1 {
    short s[7];//14
    int i;     //4
};

int main() {
    printf("%zu\n", sizeof(union Un)); //联合体大小为5,对齐4的倍数为8
    printf("%zu\n", sizeof(union Un1));//联合体大小为14,对齐4的倍数为16
    return 0;
}

4.3 联合体求大小端

一个数值,存储时需要的内存空间只要超过1个字节,就涉及顺序的问题

0x 11 22 33 44

联合体求大小端

int check_sys() {
    union {
        char c;
        int i;
    } u;

    u.i = 1;   //联合体公用一块空间 i的空间小端存储为 01 00 00 00
    return u.c;//return返回 c  c为1个字节 就是1  如果是大端返回0
}

int main() {
    int ret = check_sys;
    if (ret == 1)
        printf("小端\n");
    else
        printf("大端\n");
}

成员中最大的数据类型的大小。

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

比如:

union Un {
    char arr[5];//5 对齐数为1
    int i;      //4
};

union Un1 {
    short s[7];//14
    int i;     //4
};

int main() {
    printf("%zu\n", sizeof(union Un)); //联合体大小为5,对齐4的倍数为8
    printf("%zu\n", sizeof(union Un1));//联合体大小为14,对齐4的倍数为16
    return 0;
}

4.3 联合体求大小端

一个数值,存储时需要的内存空间只要超过1个字节,就涉及顺序的问题

0x 11 22 33 44

联合体求大小端

int check_sys() {
    union {
        char c;
        int i;
    } u;

    u.i = 1;   //联合体公用一块空间 i的空间小端存储为 01 00 00 00
    return u.c;//return返回 c  c为1个字节 就是1  如果是大端返回0
}

int main() {
    int ret = check_sys;
    if (ret == 1)
        printf("小端\n");
    else
        printf("大端\n");
}

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

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

相关文章

师承AI世界新星|7天获新加坡南洋理工大学访学邀请函

能够拜师在“人工智能10大新星”名下&#xff0c;必定可以学习到前沿技术&#xff0c;受益良多&#xff0c;本案例中的C老师无疑就是这个幸运儿。我们只用了7天时间就取得了这位AI新星导师的邀请函&#xff0c;最终C老师顺利获批CSC&#xff0c;如愿出国。 C老师背景&#xff1…

线程与信号

1.子线程会继承主线程信号处理配置&#xff0c;故信号配置可以全部放在主线程内。 2.同一信号多次触发或者嵌套触发不会嵌套执行。 3.不同信号可以嵌套触发执行。 4.kill()触发的信号由进程&#xff08;主线程&#xff09;执行&#xff0c;pthread_kill()触发的信号由参数指…

数据结构-单链表

#include<stdio.h> #include<stdlib.h>typedef struct Node {int data;struct Node* next; }Node;//创建一个头结点&#xff0c;数据域保存链表节点数 Node* init_single_list() {Node* node (Node*)malloc(sizeof(Node));node->next NULL;node->data 0; …

想知道搭建知识库有什么重点?看这篇就够了

在目前这个提倡无纸化的时代&#xff0c;搭建一个知识库已经是一种潮流。无论是个人还是企业来说&#xff0c;都是特别重要的一个工具。今天looklook就从搭建知识库的重点这方面来展开&#xff0c;详细地告诉大家该如何成功搭建一个完善的知识库。 搭建知识库的重点 1.建立素材…

ASUS华硕飞行堡垒8笔记本FX506LH LI LU FX706原装出厂 Win10系统工厂模式20H2

自带所有驱动、出厂主题壁纸LOGO、Office办公软件、MyASUS电脑管家、奥创控制中心等预装程序 所需要工具&#xff1a;16G或以上的U盘 文件格式&#xff1a;HDI,SWP,OFS,EDN,KIT,TLK多个底包 文件大小&#xff1a;10.95GB 注&#xff1a;恢复时会清空电脑上所有盘的数据&…

大小端模式

文章目录 一、概念二、举例三、判大小端和交换 一、概念 大端模式&#xff08;Big-endian&#xff09;&#xff0c;是一种数据存储方式&#xff0c;其中较高的字节&#xff08;最高有效字节&#xff09;存储在较低的内存地址&#xff0c;较低的字节&#xff08;最低有效字节&am…

php 开发微信 h5 支付 APIv3 接入超详细流程

✨ 目录 &#x1f388; 申请商户号&#x1f388; 申请商户证书&#x1f388; 设置V3密钥&#x1f388; 开通H5支付&#x1f388; 设置支付域名&#x1f388; SDK 下载&#x1f388; 第一次下载平台证书&#x1f388;非第一次下载平台证书&#x1f388; H5下单 &#x1f388; 申…

如何在WordPress网站中更改字体(8 种方法)

字体在网站设计中起着至关重要的作用。它们为设计和整体美学定下了基调&#xff0c;可以增强或削弱其外观和感觉。为您的网站选择字体集后&#xff0c;您需要知道如何更改它们。在 WordPress 中更改字体的方法有多种。如何更改它们取决于许多因素&#xff0c;包括您使用的主题类…

西安---高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测技术应用

能源是国民经济发展和人民生活必须的重要物质基础。在过去的200多年里&#xff0c;建立在煤炭、石油、天然气等化石燃料基础上的能源体系极大的推动了人类社会的发展。但是人类在使用化石燃料的同时&#xff0c;也带来了严重的环境污染和生态系统破坏。近年来&#xff0c;世界各…

9、PHP超级全局变量$_REQUEST 、$_POST、$_GET

1、PHP $_REQUEST 、$_POST用于收集HTML表单提交的数据。 以下代码演示了一个输入字段&#xff08;input&#xff09;及提交按钮(submit)的表单(form)。 当用户通过点击 "Submit" 按钮提交表单数据时, 表单数据将发送至<form>标签中 action 属性中指定的脚本文…

在阿里云平台注册一个域名

我们访问阿里云官网 阿里云 然后 我们右上角点击登录 然后 按正常操作流程登录 登录成功后 我们点击控制台 我们将鼠标 移入 右上角 图片指向的位置 我们点击域名 进入界面后点击注册域名 在输入框中输入域名内容 然后 按回车 然后弹出的列表 我们可以选一个未注册的 点击…

学习Dubbo前你要了解这些

文章目录 Dubbo的发展背景单一应用架构垂直应用架构分布式服务架构流动计算架构 RPCRPC的简单原理 DubboDubbo是什么Dubbo作者Dubbo的发展历程Dubbo架构 Dubbo发音&#xff1a; |ˈdʌbəʊ| Dubbo官方网站&#xff1a;http://dubbo.apache.org/ Dubbo是阿里巴巴开发的&#…

【Linux系统】结合有趣的小故事让你学懂生产者消费者模型

目录 由故事引入模型故事背景供货商们的矛盾市民们和供货商之间的矛盾一市民们和供货商之间的矛盾二市民们的矛盾模型总结 生产者消费者模型为什么要使用生产者消费者模型&#xff1f;生产者消费者模型的特点生产者消费者模型优点 基于BlockingQueue的生产者消费者模型C queue模…

含CPU芯片的PCB可制造性设计问题详解

CPU是中央处理器&#xff0c;Central Processing Unit 英文的缩写&#xff0c;电脑中一个最重要&#xff0c;最核心的东西&#xff0c;相当一个人的大脑&#xff0c;是用来思考、分析和计算的。目前市面上比较常见的CPU来自两个品牌&#xff0c;一个是intel公司生产的&#xff…

电脑数据恢复:恢复Windows中永久删除的文件

什么是数据恢复及其工作原理&#xff1f; 一般来说&#xff0c;数据恢复是从内部和外部硬盘、固态硬盘、USB、SD卡和其他辅助存储设备中恢复无法访问、删除、丢失、损坏的数据的过程。 删除文件后&#xff0c;你的Windows操作系统会自动将不需要的文件保存到回收…

Windows系统中数据标注软件LabelImg的安装和基本使用

文章目录 前言安装LabelImgLabelImg基本使用LabelImg支持的快捷键相关链接 前言 LabelImg是国立台湾大学&#xff08;National Taiwan University&#xff09;的Tzuta Lin主导完成&#xff0c;并基于免费软件许可MIT LICENSE发布在github上的一款计算机视觉&#xff08;Comput…

Ansible自动化运维工具的认识

目录 一、Ansible概述 二、Ansible特点 三、Ansible应用 1、使用者 2、Ansible工具集合 3、作用对象 四、Ansible的搭建 1、实验环境 2、环境准备 Ansible&#xff1a; 3、创建ssh免密交互登录 client端环境准备 五、Ansible配置 六、Ansible命令 1、ansible 实…

【C++ 重要知识点总结】表达式

表达式 1 基础 组合运算 优先级结合律 类型转换 运算符重载 左值和右值 2 算数运算符 3 逻辑和关系运算法 短路求值 逻辑与&#xff0c;当第一个判定为否的时候&#xff0c;不再执行第二个判定&#xff0c;可以用来屏蔽第二步的计算&#xff0c;代替条件判断&#xff0…

为什么很多公司都开始使用Go语言了?

越来越多的互联网大厂开始使用Go语言了&#xff0c;譬如腾讯、美团、滴滴、百度、Google、bilibili... 还有最初使用Python的字节跳动&#xff0c;甚至已经全面拥向Go了。这么多国内外首屈一指的公司&#xff0c;都在开始使用它了&#xff0c;它到底有什么优势呢&#xff1f;这…

03.MySQL——索引和事务

索引 索引的概念 索引可以提高数据库的性能。不用加内存&#xff0c;不用改程序&#xff0c;不用调sql&#xff0c;只要执行正确的 create index &#xff0c;查询速度就可能提高成百上千倍。但是查询速度的提高以插入、更新、删除的速度为代价。索引的价值在于提高一个海量数…