【C语言进阶】结构体、位段、枚举、以及联合(共用体)的相关原理与使用

news2024/11/24 14:47:31

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:C语言进阶
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 1.结构体
    • 1.1 概述:
    • 1.2 结构的声明:
    • 1.3 特殊声明:
    • 1.4 结构的自引用:
    • 1.5 结构的定义与初始化:
    • 1.6 `重点`结构体内存对齐:
    • 1.7 修改默认对齐数:
    • 1.8 结构体传参:
  • 2.位段
    • 2.1 位段概述:
    • 2.2 位段的内存分配:
    • 2.3 位段的跨平台问题:
  • 3.枚举
    • 3.1 定义:
    • 3.2 枚举类型的优点:
    • 3.3 枚举类型的使用:
  • 4.联合(共用体)
    • 4.1 联合类型的定义:
    • 4.2 联合类型的特点:
    • 4.3 联合类型大小的计算:
  • 5.总结:

1.结构体

1.1 概述:

C 语言允许用户自己指定这样一种数据结构,它由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体,它相当于其它高级语言中记录。结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

1.2 结构的声明:

以描述 “ 学生 ”为例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//结构体的声明:
struct student
{
	char name[20];
	int age;
	char sex[5];
	float score;
}s1,s2;
//定义结构体变量s1、s2
//此处定义的结构体变量是全局的
struct student s3, s4;
//定义结构体变量s3、s4
//此处定义的结构体变量等同于声明时定义,也是全局的
int main()
{
	struct student s5, s6;
	//定义结构体变量s5、s6
	//此处定义的结构体变量是局部的
	return 0;
}

1.3 特殊声明:

关于结构体的不完全声明,即匿名结构体类型

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct
//没有声明结构体标签,即为匿名结构体类型
{
	char name[20];
	int age;
	char sex[5];
	float score;
}student = { "Zhang",21,"Man",91.7 };
//匿名结构体类型必须在生声明的同时进行定义
 
int main()
{
	printf("%s %d %s %.1f\n", student.name, student.age, student.sex, student.score);
	return 0;
}

我们把这种在声明时省略掉结构体标签的结构体称为匿名结构体类型,在使用这种方式进行声明时,由于没有声明结构体标签,导致一旦该结构体结束声明,将无法再次进行定义,所以对于该类型的结构体来说,就必须在声明结构体的同时进行定义(可以不初始化)
再来看下面这个例子:

//结构体类型1:
struct
{
	char name[20];
	int age;
	char sex[5];
	float score;
}x;
 
//结构体类型2:
struct
{
	char name[20];
	int age;
	char sex[5];
	float score;
}*p;

在这个示例中,虽然两个结构体类型内的结构体成员完全一样,但因为两者都使用了匿名结构体的声明方式,编译器会把上面的两个声明当成完全不同的两个类型
于是在下面的代码中将被视为非法

p = &x; 
//一种类型的指针指向另一种不同类型,将被视为非法

1.4 结构的自引用:

结构的自引用就是指结构体在自己的声明中引用了自己的一种声明方式。

struct Test
{
	int data;
	struct Test n;
};
int main()
{
	struct Test n;
	return 0;
}

我们说这种引用方式是非法的。这是因为,当我们这样进行引用后,在我们定义结构体变量时,会进行自引用,但在自引用中又嵌套了对自身的引用,如此循环往复,而编译器并不知道该在何时停止自引用。

正确的自引用形式:

struct Test
{
	int data;
	struct Test* NEXT;
    //使用指针指向确定的引用空间
};
int main()
{
	struct Test n;
	return 0;
}

当我们在进行结构体变量的定义时同样进行了自引用,不同的是这一次我们使用了一个指针,指向了下一个结构体变量的空间,而在这次指向之后,指针指向的空间被固定,不再指向其它空间,如此就实现了真正的结构体自引用。
同时,我们还可以结合关键字 typedef 进行使用:

typedef struct Test
{
	int data;
	struct Test* NEXT;
	//但在这里必须仍使用struct Test
	//在结构体声明结束后才会进行重命名
}Test;
//使用tepydef关键字,将struct Test类型重命名为Test类型
 
int main()
{
	Test n;
	//经过重命名,在进行定义时可以直接使用重命名后的类型名进行定义
	return 0;
}

我们可以结合关键字 typedef 来将我们声明的结构体变量进行重命名,方便我们对结构体变量定义与初始化。但要注意的是,在使用 typedef 时,在结构体声明内部进行自引用时,仍需写成完全形式,这是因为,只有在结构体声明结束后才会对我们声明的结构体类型进行重命名

1.5 结构的定义与初始化:

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct student
{
	char name[20];
	int age;
	char sex[5];
	float score;
 
}s1 = { "Zhang",21,"Man",98.4 };
//初始化结构体变量s1,此处的结构体变量是全局的
 
struct student s2 = { "Wang",20,"Woman",99.5 };
//初始化结构体变量s2,此处初始化的结构体变量等同于声明时初始化,也是全局的
 
int main()
{
	struct student s3 = { "Jiao",21,"Man",67.2 };
	//初始化结构体变量s3,此处的结构体变量是局部的
 	printf("%s %d %s %.1lf\n", s1.name, s1.age, s1.sex, s1.score);
	printf("%s %d %s %.1lf\n", s2.name, s2.age, s2.sex, s2.score);
	printf("%s %d %s %.1lf\n", s3.name, s3.age, s3.sex, s3.score);
	return 0;
}

1.6 重点结构体内存对齐:

经过上面的学习,我们就已经基本掌握了结构体的使用了。接下来我们将要深入研究结构体大小的计算过程,即结构体内存对齐,而这也是近年来的热门考点。
先来看看下面这段计算结构体变量大小的代码:

#include<stdio.h>
struct test1
{
	char a;
	int b;
	char c;
}test1;
struct test2
{
	char d;
	char e;
	int f;
}test2;
int main()
{
	printf("The size of test1 is %d\n", sizeof(test1));
	printf("The size of test2 is %d\n", sizeof(test2));
	return 0;
}

我们将其编译运行起来看看结果:

The size of test1 is 12
The size of test1 is 8

我们看到,实际的计算结果与我们的猜想大相径庭,那么到底是哪里出现了问题呢?这就是我们在这里需要研究的内容:结构体内存对齐
要想弄清楚究竟是如何进行结构体变量大小计算的,我们首先得掌握

结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。(偏移量:该成员的存放地址与结构体空间起始地址之间的距离)
  2. 其他成员变量要对齐到对齐数的整数倍的地址处。
  3. 对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
  4. 对齐数在VS中的默认值为8
  5. 结构体总大小为最大对齐数的整数倍
  6. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍。

知晓了结构体的对齐规则,我们再回过头来分析上面的结构体变量大小计算过程。
分析如图:
在这里插入图片描述
但是我们发现,这样的方式造成了很大程度上的空间浪费,以 test1 为例,12个字节的大小中有六个字节的空间申请了但却没有被使用。那么为什么还要采用这样的办法呢?

主要有以下两个原因:

  1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。通俗来说结构体的内存对齐就是一种用空间换时间的处理方法。而我们能做的,就只有以上面的 test1 与 test2 为例,尽可能的选取 test2 这样,使占用空间小的成员尽可能的集中在一起。

1.7 修改默认对齐数:

在我们的代码编写过程中,默认的对齐数可能会不够合适。而当这个时候,我们就可以通过使用下面这个预处理指令来修改我们的默认对齐数:

#pragma pack(8)
//修改默认对齐数为8

我们也可以通过该指令在修改过默认对齐数之后,取消设置的默认对齐数,将其还原:

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

1.8 结构体传参:

结构体传参与函数传参类似,我们直接来看下面的示例:

#include<stdio.h>
struct TEST
{
	int data[1000];
	int num;
};
struct TEST test = { {1,2,3,4}, 1000 };
//结构体传参
void Print1(struct TEST test)
{
	printf("%d\n", test.num);
}
//结构体地址传参
void Print2(struct TEST* p)
{
	printf("%d\n", p->num);
}
int main()
{
	Print1(test);  //传结构体
	Print2(&test); //传地址
	return 0;
}

而在上面这段代码中,我们一般认为 Print2 函数更为优秀。原因是当函数传参的时候,参数是需要压栈的,在这个过程中就会产生时间和空间上的系统开销。如果传递一个结构体对象时结构体过大,那么将会导致参数压栈的的系统开销较大,最终将会导致程序性能的下降。

2.位段

结构体实现位段

2.1 位段概述:

位段(bit-field)以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作

位段的声明和结构体十分相似,但同时有两个不同点:

  1. 位段的成员必须是 intsigned intunsigned intchar 类型。
  2. 位段的成员名后边有一个冒号和一个数字(该成员所占内存空间大小,单位为 bit位)。
#include<stdio.h>
struct test
{
	int _a : 2;
    //成员 a 只占用 2 个比特位
	signed int _b : 5;
    //成员 b 只占用 5 个比特位
	unsigned int _c : 10;
    //成员 c 只占用 10 个比特位
	char _d : 4;
    //成员 d 只占用 4 个比特位
};
int main()
{
	printf("The size of struct test is %d\n", sizeof(struct test));//4
	return 0;
}

优点:能够节省大量的空间,通过有条件地(根据实际使用需求)限制每个变量所占内存空间的大小,从而减少了整体结构的空间占用

2.2 位段的内存分配:

位段存在的意义便是最大程度上去减少空间的浪费,所以在进行存储时,位段不会进行内存对齐操作。那么位段的内存空间是如何进行分配的呢?
注意位段的内存分配并没有严格的规则,在不同的编译器上产生的结果可能不同,我们今天的讲解,将以Visual Studio 2019 为例进行研究。

首先需要知道位段进行内存分配的规则:
1. 位段的成员可以是 intunsigned intsigned int 或者是 char(属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
4. 位段的内存分配是逐4字节(一个 int 类型的大小)进行分配的。
5. 当字节内空间不足以放下下一个成员变量时,剩余的空间不再使用,而是再从内存中申请一个字节的空间继续分配。
6. 不同类型(charint类型)数据进行存储时将会另起4个字节(一个 int 类型的大小)进行存储。
#include<stdio.h>
struct test
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s={0};
	s.a=10;
	s.b=12;
	s.c=3;
	s.d=4;
	return 0;
}

分析如图:
在这里插入图片描述在这里插入图片描述

至此,该位段结构的内存分配结束,共占据3个char 类型数据的大小,即 3 个字节

2.3 位段的跨平台问题:

我们上面说过,位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段,并且在未来位段结构的使用过程中,我们一定要提前仔细地研究好位段在不同编译器下使用时,究竟是如何进行内存分配的,再结合我们的实际需求实现跨平台使用。

而在位段进行跨平台使用时,我们通常需要注意以下四个关键点:

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

总结下来,跟结构相比,位段可以达到跟结构相同的效果,并且可以更好的利用空间,但同时存在着跨平台问题

3.枚举

枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常但不总是重叠。是一个被命名的整型常数的集合。简单来说就将某种特定类型的对象一一进行列举。
枚举的声明与结构和联合相似, 其形式为:

enum 枚举名{
标识符(=整型常数),
标识符(=整型常数),

标识符(=整型常数)
} 枚举变量;

3.1 定义:

#include<stdio.h> 
//枚举类型1:
enum Sex
{
	MALE,
	FEMALE,
	SECRET
}s1 = MALE;
//声明时进行定义与初始化(全局)
enum Sex s2 = FEMALE;
//枚举类型2:
enum Day
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
int main()
{
	enum Day s3 = Mon;
	//定义与初始化(局部)
	return 0;
}

我们可以看到,枚举类型的声明、定义与初始化与结构十分类似。然后我们再来看一看枚举类型内部各成员的值,我们以日期为例:

#include<stdio.h>
enum Day
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
int main()
{
    //打印各成员的值:
	printf("The value of Mon  is %d\n", Mon);
	printf("The value of Tues is %d\n", Tues);
	printf("The value of Wed  is %d\n", Wed);
	printf("The value of Thur is %d\n", Thur);
	printf("The value of Fri  is %d\n", Fri);
	printf("The value of Sat  is %d\n", Sat);
	printf("The value of Sun  is %d\n", Sun);
	return 0;
}

将上面这个示例编译运行起来看看结果的反馈:
在这里插入图片描述
我们看到,枚举类型内部各成员的默认值是从 0 开始依次递增的。
但是成员的值不仅限于默认值,同时也允许我们在定义时给各成员附合适的初值:

#include<stdio.h>
enum Day
{
	Mon,
	Tues=5,
	Wed,
	Thur,
	Fri,
	Sat=15,
	Sun
};
int main()
{
	printf("The value of Mon  is %d\n", Mon);
	printf("The value of Tues is %d\n", Tues);
	printf("The value of Wed  is %d\n", Wed);
	printf("The value of Thur is %d\n", Thur);
	printf("The value of Fri  is %d\n", Fri);
	printf("The value of Sat  is %d\n", Sat);
	printf("The value of Sun  is %d\n", Sun);
	return 0;
}

在这里插入图片描述
我们可以依照上面这种方式对枚举类型成员的初值进行修改:
我们看到,经过修改本应按序赋值为 1 的枚举成员 Tues 被赋值成了 5 ,于是接下来的成员就从 5 开始依次赋值,直到成员 Sat 被赋值为 15 后,接下来的成员就从 15 开始依次递增。

3.2 枚举类型的优点:

枚举类型的成员均为常量,不可在使用中被修改,那么我们同样可使用宏 #define 去定义常量,为什么非要使用枚举类型呢?
这是因为,相比于宏,枚举类型具有很多优点:

优点:

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

3.3 枚举类型的使用:

同时我们要注意,在使用枚举类型时只能用枚举常量给枚举变量赋值,只有这样才不会出现类型差异:

#include<stdio.h> 
//声明枚举类型
enum TEST
{
	test1,
	test2,
	test3
};
//其中test1、test2、test3为枚举常量
int main()
{
	//定义枚举变量:
	enum TEST t;
	//使用枚举常量给枚举变量赋值:
	t = test3;
	//验证赋值结果:
	printf("The value of t is %d\n", t);
	return 0;
}

4.联合(共用体)

在进行某些算法的编程的时候,需要将几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术使几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作 “ 联合体 ” 类型结构,简称联合,也叫共用体。

4.1 联合类型的定义:

联合是一种特殊的自定义类型,这种类型定义的变量也包含有一系列的成员,但不同的是这些成员共用同一块空间(也被称作共用体)
它的定义也基本与结构体一致:

#include<stdio.h>
union TEST
{
	char a;
	int b;
}test;
//在定义联合体的同时定义联合体变量test
int main()
{
	//查看联合体的占用空间:
	printf("The size of test is %d\n", sizeof(test));
	//查看联合体成员的存储地址:
    printf("The address of test is %p\n", &test);
	printf("The address of   a  is %p\n", &test.a);
	printf("The address of   b  is %p\n", &test.b);
	return 0;
}

在这里插入图片描述

但不同的是,我们编译运行后发现,联合体成员 char 类型变量 a 与 int 类型变量 b 共同占用同一片空间(一个 int 类型所占的空间):
这种方式定义的联合体结构,是三种结构中最节省空间的一种,但同时,极致的空间节省能力导致了它在使用时需要满足的条件极为苛刻。

4.2 联合类型的特点:

联合体最大的特点就是,联合体的成员是共用同一块内存空间的,则联合至少得有足够的空间容纳最大的成员,这样一个联合变量的大小就至少得是最大成员的大小。
既然联合体的大小会随着内部成员大小的变化而变化,那么是不是联合体类型也可以通过判断内容大小,来帮助我们判断机器的大小端存储模式呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int check_sys()
{
	union CHECK
	{
		char check1;
		int check2;
	}check;
	check.check2 = 1;
	return check.check1;
}
 
int main()
{
	if (1 == check_sys())
	{
		printf("您的机器采用小端存储模式!\n");
	}
	else
	{
		printf("您的机器采用大端存储模式!\n");
	}
	return 0;
}

在这里插入图片描述

我们将其编译运行发现,该思路可以帮助我们检查机器的大小端存储模式

4.3 联合类型大小的计算:

联合体类型的大小计算需要按照以下规则进行计算

  1. 联合的大小至少是最大成员的大小。
  2. 当最大成员大小不是最大对齐数的整数倍时,要对齐到最大对齐数的整数倍。
#include<stdio.h>
//联合体1:
union TEST1
{
	char c[5];
	int i;
};
//联合体2:
union TEST2
{
	short c[7];
	int i;
};
int main()
{
	//检查联合体的大小:
	printf("The size of TEST1 is %d\n", sizeof(union TEST1));
	printf("The size of TEST2 is %d\n", sizeof(union TEST2));
	return 0;
}

1.在联合体 TEST1 中,占用空间最大的成员是 char 类型数组 c ,且其中含有 5 个元素,则其所占空间大小为 5 个字节,而我们都知道 VS 的对齐数默认为 8 ,则将会对齐至默认对齐数的整数倍,即 8 个字节。
2.而联合体 TEST2 中,占用空间最大的成员是 short 类型数组 c ,且其中含有 7 个元素,则其所占空间的大小为 14 个字节,那么就将会对齐至对齐数的整数倍,即 16 个字节

5.总结:

今天我们对结构体的相关原理与使用等知识又有了新的了解,学习了结构体、位段、枚举、以及联合(共用体)的相关知识,完成了通过联合体类型判断机器的大小端存储模式,希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

代码随想录【Day22】| 235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点

235. 二叉搜索树的最近公共祖先 题目链接 题目描述&#xff1a; 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 …

别担心ChatGPT距离替代程序猿还有距离

经过多天对chat-GPT在工作的使用&#xff0c;我得出一个结论&#xff0c;它睁眼瞎说就算了&#xff0c;它还积极认错&#xff0c;绝不改正&#xff0c;错误答案极具误导性&#xff0c;啥也不说了&#xff0c;请看图。 经过N次较量它固执的认为 0011 1101 0110 0101在最高位是左…

【python】考前复习,python基础语法知识点整理

文章目录1.常量与表达式2.变量和数据类型创建变量数据类型动态类型数据类型的转换3.注释4.字符串字符串的定义方式字符串的拼接字符串的格式化①字符串格式化的精度控制字符串的格式化②对表达式进行格式化5.从控制台输入(input)6.运算符算术运算符赋值运算符布尔类型和比较运算…

【Spring Cloud Alibaba】006-OpenFeign

【Spring Cloud Alibaba】006-OpenFeign 文章目录【Spring Cloud Alibaba】006-OpenFeign一、概述1、Java 项目实现接口调用的方法HttpclientOkhttpHttpURLConnectionRestTemplate WebClient2、Feign 概述二、Spring Cloud Alibaba 快速整合 OpenFeign1、添加依赖2、启动类加注…

STM32开发(12)----CubeMX配置WWDG

CubeMX配置窗口看门狗&#xff08;WWDG&#xff09;前言一、窗口看门狗的介绍二、实验过程1.STM32CubeMX配置窗口看门狗2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对窗口看门狗定时器进行配置的方法。门狗本质上是一个定时器&#xff0c;提供了更高的安…

物联网在物流行业中的应用

物流管理需要同时监控供应链、仓储、运输等多项活动&#xff0c;然而许多因素会影响物流流程本身并导致延迟。为了简化流程和提高客户满意度&#xff0c;一些行业领导者和决策者积极创新&#xff0c;不断评估并使用物联网对物流流程的成本效益进行深入优化。在本文中&#xff0…

初识MySQL下载与安装【快速掌握知识点】

目录 前言 MySQL版本 MySQL类型 MySQL官网有.zip和.msi两种安装形式&#xff1b; MySQL 下载 1、MySQL 属于 Oracle 旗下产品&#xff0c;进入Oracle官网下载 2、点击产品&#xff0c;找到MySQL 3、进入MySQL页面 4、点击Download&#xff08;下载&#xff09;&#x…

PHP面向对象03:命名空间

PHP面向对象03&#xff1a;命名空间一、命名空间基础二、子空间三、命名空间访问1. 非限定名称2. 限定名称3. 完全限定名称四、全局空间五、命名空间应用六、命名空间引入一、命名空间基础 namespace&#xff0c;是指人为的将内存进行分隔&#xff0c;让不同内存区域的同名结构…

在uniapp 中使用Ucharts 进行可视化图表开发,折线统计图。

首先我们得 在uniapp 插件市场中找到Ucharts 这款插件&#xff0c;我这里是使用uni_modules导入这款插件案例1:我们这时可以在页面中使用组件的方式进行使用<qiun-data-charts type"area" :chartData"chartData" :opts"opts"/>Js逻辑的代…

基于vue考研助手网站

可定制框架:ssm/Springboot/vue/python/PHP/小程序/安卓均可开发目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 3 系统分析 6 3.1系统可行性分析 6 3.1.1经济可行性 6 3.1.2技术可行性 6 3.1.3运行可行性 6 …

我的 System Verilog 学习记录(3)

引言 本文简单介绍 System Verilog 语言的 TestBench。 前文链接&#xff1a; 我的 System Verilog 学习记录&#xff08;1&#xff09; 我的 System Verilog 学习记录&#xff08;2&#xff09; testbench 的目的何在 &#xff1f; testbench 可以让我们通过仿真验证设计…

Qt 工程 pro文件

工作中&#xff0c;感觉pro文件的有些内容真不太懂&#xff0c;现系统性的学习一下。于此备录&#xff0c;分享共勉。 为了更好的理解&#xff0c;先创建一个简单的工程作为实践。 【1】创建一个pro文件 1.1 新建proDemo工程。步骤如下&#xff1a;Qt Creator--->New Pro…

数据结构初阶——时间复杂度与空间复杂度

时间复杂度与空间复杂度1. 算法效率1.1 如何衡量一个算法的好坏1.2算法的复杂度2.时间复杂度2.1 时间复杂度的概念2.2 大O的渐进表示法2.3常见时间复杂度计算举例实列1&#xff1a;实列2&#xff1a;实列3&#xff1a;实列4&#xff1a;实列5&#xff1a;实列6&#xff1a;实列…

k8s service的底层实现

承接上文同一个node中pod之间如何通信&#xff1f;当前的集群中给2个apache pod注册了一个service&#xff0c;这个地址是10.152.183.151&#xff0c;在ubuntu的pod中测试这个ip是可以通信的&#xff0c;it work来源于本机的pod&#xff0c;多访问几次发现会随机的把请求定向到…

远程控制详细教程,同时支持手机控制

​“我需要一些帮助&#xff0c;目前我因为休假旅游去了&#xff0c;需要临时远程办公。我工作的电脑运行的是Windows 10系统&#xff0c;我如何操作才能远程控制公司的电脑进行远程办公&#xff1f;我之前没用过远程控制相关的工具&#xff0c;什么简单的方法可以远程控制另一…

别只会搜日志了,求你懂点检索原理吧

别只会搜日志了&#xff0c;求你懂点检索原理吧 本篇主要内容如下&#xff1a; 前言 项目中我们总是用 Kibana 界面来搜索测试或生产环境下的日志&#xff0c;来看下有没有异常信息。Kibana 就是 我们常说的 ELK 中的 K。 Kibana 界面如下图所示&#xff1a; 但这些日志检索…

内网渗透(五十一)之域控安全和跨域攻击-跨域攻击介绍

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

软件测试面试题 —— 整理与解析(1)

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;&#x1f30e;【Austin_zhai】&#x1f30f; &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xf…

数据库浅谈之向量化

数据库浅谈之向量化 HELLO&#xff0c;各位博友好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 这里是数据库浅谈系列&#xff0c;收录在专栏 DATABASE 中 &#x1f61c;&#x1f61c;&#x1f61c; 本系列阿呆将记录一些数据库领域相关的知识 &#x1f3…

Zabbix“专家坐诊”第182期问答汇总

问题一&#xff1a; Q&#xff1a;像烽火、浪潮这种没有ilo的设备怎么监控他们的硬件状态呢&#xff1f; A&#xff1a;如果没有ilo&#xff0c;可以使用其他硬件监控软件&#xff0c;例如HP Insight Manager、IBM Director、Dell OpenManage等。这些软件可以帮助您监控硬件状…