C语言深度解析--操作符

目录

操作符

1.算数操作符

2.移位操作符

左移操作符<<:

右移操作符>>:

3.位操作符

按位与&:

按位或 | :

按位异或 ^ :

4.赋值操作符

5.单目操作符

6.关系操作符

7.逻辑操作符

8.条件操作符

9.逗号操作符

10.下标引用,函数调用和结构成员

下标引用操作符:

函数调用操作符:

结构成员操作符:

表达式求值

隐式类型转换

算术转换

操作符的属性


操作符

1.算数操作符

C语言提供了常用的操作符:+  -  *  /  %

除了%操作符,其余几个操作符都是既适用于浮点类型又适用于整数类型

当/操作符的两个操作数都是整数时,它执行整除运算,在其他情况下则执行浮点数除法

%为取模操作符,它接受两个整型操作符,把左操作数除以右操作数,但它返回的值是余数而不是商

int main()
{
	//对于/操作符如果两个操作数都为整数,执行整数除法,而只要有浮点数执行的就是浮点数除法
	int a = 3 / 2;
	printf("%d",a);//1

	int a = 3.0 / 2;
	printf("%d",a);//1

	float a = 3.0 / 2;
	printf("%f",a);//1.500000

	float a = 3 / 2;
	printf("%f\n",a);//1.000000

	//%操作符的两个操作数必须为整数。返回的是整除之后的余数
	int a = 9 % 2;
	printf("%d\n",a);//1

	return 0;
}

2.移位操作符

移位操作符(二进制补码运算,运算结果转原码)
正整数的原码,反码,补码都相同
负整数的原码,反码,补码是要计算的;反码:原码的符号位不变,其他位取反;补码:反码+1
整数在内存中,存储的是二进制的补码,移位操作符,移动的是存储在内存当中的补码

左移操作符<<:

移位规则:左边抛弃,右边补0

int main()
{
	//左移<<:左边抛弃,右边补0
	int a = 5;//5的补码:00000000 00000000 00000000 00000101
	int b = a << 1;//00000000 00000000 00000000 00000101,左移一位:00000000 00000000 00000000 00001010(最左面的0舍弃,最右面补0),正数的原返补码相同,得b=10

	printf("%d\n", a);//5
	printf("%d\n", b);//10

	//负数的补码转原码:
	//如果补码的最高位是1,说明这个补码所代表的数是负数,将补码除符号位外的所有位取反(0变成1,1变成0)得到反码,在反码的基础上加1,得到原码
	
	int a = -5;//-5的原码:10000000 0000000 0000000 00000101,-5的反码:11111111 11111111 11111111 11111010,-5的补码:11111111 11111111 11111111 11111011
	int b = a << 1;//-5的补码:11111111 11111111 11111111 11111011,左移一位:11111111 11111111 11111111 11110110,求反码:10000000 00000000 00000000 00001001,求原码:10000000 00000000 00000000 00001010,得b=-10

	printf("%d\n", a);//-5
	printf("%d\n", b);//-10
    
    return 0;
}

右移操作符>>:

移位规则:

逻辑右移:左边用0填充,右边丢弃
算术右移:左边用原符号位填充,右边丢弃
当前编译器在右移的时候采用算术右移

int main()
{
	//右移>>
	//逻辑右移:左边用0填充,右边丢弃
	//算术右移:左边用原符号位填充,右边丢弃
	//当前编译器在右移的时候采用算术右移

	//int a = 5;//5的补码:00000000 00000000 00000000 00000101
	//int b = a >> 1;//00000000 00000000 00000000 00000101,右移一位:00000000 00000000 00000000 00000010,正数的原返补码相同,得2

	//正数的算术右移和逻辑右移没有区别
	//printf("%d\n", a);//5
	//printf("%d\n", b);//2,算数右移

	int a = -5;//-5的原码:10000000 0000000 0000000 00000101,-5的反码:11111111 11111111 11111111 11111010,-5的补码:11111111 11111111 11111111 11111011
	int b = a >> 1;//-5的补码:11111111 11111111 11111111 11111011,右移一位:11111111 11111111 11111111 11111101,求反码:10000000 00000000 00000000 00000010,求原码:10000000 00000000 00000000 00000011,得b=-3

	printf("%d\n", a);//-5
	printf("%d\n", b);//-3,算数右移

	return 0;
}

标准说明:无符号值执行的所有移位操作都是逻辑移位,但对于有符号值,到底是采用逻辑移位还是算数移位取决于编译器

对于移位运算符,不要移动负数位,这个是标准未定义的,如:int num=10; num>>-1;

3.位操作符

位操作符有:&  |  ^,它们分别执行AND,OR和XOR操作

它们要求操作数为整数类型,它们对操作数对应的位进行指定的操作,每次对左右操作数的各一位进行操作

按位与&:

按位与&:a和b中只要有0就为0,两个都为1时才为1

int main()
{
	int a = 3;//3的补码:00000000 00000000 00000000 00000011
	int b = -5;//-5的原码:10000000 00000000 00000000 00000101,-5的反码:11111111 11111111 11111111 11111010,-5的补码:11111111 11111111 11111111 11111011

	//按位与&:a和b中只要有0就为0,两个都为1时才为1
	int c = a & b;
	//a:00000000 00000000 00000000 00000011
	//b:11111111 11111111 11111111 11111011
	//&:00000000 00000000 00000000 00000011->得3

	printf("%d\n", c);//3

	return 0;
}

按位或 | :

按位或 |:a和b中只要有1就为1,两个都为0时才为0

int main()
{
	int a = 3;//3的补码:00000000 00000000 00000000 00000011
	int b = -5;//-5的原码:10000000 00000000 00000000 00000101,-5的反码:11111111 11111111 11111111 11111010,-5的补码:11111111 11111111 11111111 11111011

	//按位或|:a和b中只要有1就为1,两个都为0时才为0
	int d = a | b;
	//a:00000000 00000000 00000000 00000011
	//b:11111111 11111111 11111111 11111011
	//|:11111111 11111111 11111111 11111011,求反码:10000000 00000000 00000000 00000100,求原码:10000000 00000000 00000000 00000101,得-5

	printf("%d\n", d);//-5
}

按位异或 ^ :

按位异或 ^ :相同为0,相异为1

int main()
{
	int a = 3;//3的补码:00000000 00000000 00000000 00000011
	int b = -5;//-5的原码:10000000 00000000 00000000 00000101,-5的反码:11111111 11111111 11111111 11111010,-5的补码:11111111 11111111 11111111 11111011

	//按位异或:相同为0,相异为1
	int d = a ^ b;
	//a:00000000 00000000 00000000 00000011
	//b:11111111 11111111 11111111 11111011
	//^:11111111 11111111 11111111 11111000,求反码:10000000 00000000 00000000 00000111,求原码:10000000 00000000 00000000 00001000,得-8

	printf("%d\n", d);//-8
}

异或运算三个性质:

  1. 任何数和 0做异或运算,结果仍然是原来的数
  2. 任何数和其自身做异或运算,结果是 0
  3. 异或运算满足交换律和结合律

案例:不能创建临时变量(第三个变量),实现两个数的交换

int main()
{
	//a^a=0
	//0^a=a
	int a = 10;
	int b = 20;
	a = a ^ b;
	b = a ^ b;//b=a^b^b=a^0=a
	a = a ^ b;//a=a^b^a=a^a^b=0^b=b

	printf("a=%d b=%d", a, b);//20 10

	return 0;
}

4.赋值操作符

赋值操作符可以连续使用

赋值操作符的结合性(求值的顺序)是从右到左

int main()
{
	int a = 10;
	int x = 0;
	int y = 20;

	a = x = y + 1;//连续赋值
	//等价于
	x = y + 1;
	a = x;

	return 0;
}

复合赋值符:

+=   -=   *=   /=   %=   <<=   >>=   &=   ^=   |=

int main()
{
	a = a >> 1;
	a >>= 1;

	a = a & 4;
	a &= 4;

	return 0;
}

5.单目操作符

!:!操作符对它的操作数执行逻辑反操作;如果操作数为真,则结果为假,如果操作数为假,则结果为真。和关系操作符一样,这个操作符实际上产生一个整型结果,0或1

C语言中0表示假,非0表示真
C语言中C99之前没有表示真假的类型,C99中引用了bool类型:<stdbool.h>

int main()
{
	_Bool flag1 = false;
	_Bool flag2 = true;

	if (flag2)
	{
		printf("hehe\n");
	}

	return 0;
}

~:~操作符对整型类型的操作数进行求补操作,操作数中所有原先为1的位变为0,所有原先为0的位变为1

int main()
{
	int a = 0;
	printf("%d\n", ~a);//-1
	//00000000 00000000 00000000 00000000:0的补码
	//11111111 11111111 11111111 11111111:按位取反
	//10000000 00000000 00000000 00000000:反码
	//10000000 00000000 00000000 00000001:原码->-1

	return 0;
}

为什么while(^scanf("%d",&n))可以终止循环?

在while(scanf("%d",&n)!=EOF){...}中,scanf()读取失败的时候,返回EOF,而EOF对应的值等于-1
而~(-1)的值为0;因为-1的补码:11111111 11111111 11111111 11111111按位取反后为00000000 00000000 00000000 00000000对应的原码为0

-:-操作符产生操作数的负值

+:+操作符产生操作数的值

&:&操作符产生它的操作数的地址

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

int main()
{
	//&:取地址
	//变量取地址
	int a = 10;
	int* pa = &a;

	//数组取地址
	//&数组名:取出的是数组的地址,数组名表示整个数组
	int arr[10] = { 0 };
	&arr;//取出数组的地址,数组的地址应该存放到数组指针中去

	//结构体取地址
	struct S s = { 0 };
	struct S* ps = &s;
}

*:*操作符是间接访问操作符(解引用操作符),它与指针一起使用,用于访问指针所指向的值

int main()
{
	int a = 10;
	int* pa = &a;


	//*解引用操作符(间接访问操作符)
	*pa = 20;//把a改成20

	printf("%d\n",a);//20
}

sizeof:sizeof操作符判断它的操作数的类型长度,以字节为单位。操作数既可以是个表达式(常量是单个变量),也可以是两边加括号的类型

sizeof是一个操作符,不是函数

int main()
{
	int a = 10;
	//类型不可省略,变量可省略
	printf("%d\n",sizeof(a));//4
	printf("%d\n", sizeof a );//4
	printf("%d\n", sizeof(int));//4
	//printf("%d\n", sizeof int );//不可省略

	int arr[10] = {0};
	printf("%d\n",sizeof(arr));//40

	int a = 10;
	short s = 0;
	
	printf("%d\n", sizeof(s = a + 2));//2,sizeof()中的表达式不参与计算,看向s
	printf("%d\n", sizeof(a = s + 2));//4,sizeof()中的表达式不参与计算,看向a
	printf("%d\n", s);//0

	//sizeof和数组
	//数组作为函数参数传递时,传入的是数组首地址,并非是数组本身
	//当数组作为函数参数传递时,不能在函数中用sizeof求数组长度

	return 0;
}

(类型):(类型)操作符被称为强制类型转换,它用于显示地把表达式的值转换为另外的类型,如果要对整个表达式的结果进行强制类型转换,必须把整个表达式用括号括起来

int main()
{
	int a = (int)3.14;
	printf("%d\n",a);//3

	return 0;
}

++:前置++,先++,后使用,后置++,先使用,后++

--:前置--,先--,后使用,后置--,先使用,后--

int main()
{
	int a = 3;
	//++a相当于a=a+1
	int b = ++a;//前置++,先++,后使用
	printf("%d\n",b);//4
	printf("%d\n",++a);//5

	int b = a++;//后置++,先使用,后++
	printf("%d\n", b);

	int b = --a;//前置--,先--,后使用
	int b = a--;//后置--,先使用,后--

	return 0;
}

6.关系操作符

关系操作符有:>   <   >=   <=   !=   ==

这些操作符产生的结果都是一个整型值,而不是布尔值。如果两端的操作数符合操作符指定的关系,表达式的结果为1,否则,表达式的结果为0。关系操作符的结果是整型值,所以它可以赋值给整型变量,但通常它们用于if或while语句中,作为测值表达式。

在C语言中,在测试相等性的地方出现赋值是合法的,它并非是一个语法错误

==:用于判断相等,不能用于两个字符串的判断相等
=:用于赋值

int main()
{
	if ("abcdef" == "abbq")//不能用该方式,应该用strcmp:专门用于比较字符串的大小,比较对应位置上字符的大小,不是比较长度
	{

	}
	return 0;
}

7.逻辑操作符

逻辑操作符:&&   ||

它们用于对表达式求值,测试它们的值是真是假

&&操作符的左操作数总是首先进行求值,如果为真,就紧接着对右操作数进行求值;如果左操作数的值为假,那么右操作数便不再进行求值,因为整个表达式的值肯定是假的,右操作数的值已经无关紧要。

||操作符首先对左操作数进行求值,如果它的值是真,右操作数便不再求值,因为整个表达式的值此时已经确定。这个行为常常被称为“短路求值”

int main()
{
	int a = 3;
	int b = 5;
	if (a && b)//为真
	{
		printf("hehe\n");
	}

	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;//&&:只要碰到一个为假,后面的就不再计算;因为a为后置++,则先使用,后++,所以a=0为假,后面则不再计算
	printf("a=%d b=%d c=%d d=%d\n", a, b, c, d);//1 2 3 4

	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i=a++||++b||d++;//||:直到碰到一个为真,才结束后面的运算
	printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);//1 3 3 4

	return 0;
}

位操作符与逻辑操作符的区别:

  1. 逻辑操作符具有短路性质,如果表达式的值根据左操作数便可决定,它就不再对右操作数进行求值;与之相反,|和&操作符两边的操作数都需要进行求值
  2. 逻辑操作符用于测试零值和非零值,而位操作符用于比较它们的操作数中对应的位

8.条件操作符

exp1  ?  exp2  :  exp3

首先计算的是exp1,如果它的值为真(非零值),那么整个表达式的值就是exp2的值,exp3不会进行求值。但是,如果exp1的值为假(零值),那么整个表达式的值就是exp3的值,exp2不会进行求值

int main()
{
	int a = 3;
	int b = 0;

	b = (a > 5 ? 3 : -3);

	printf("%d\n",b);//-3
	return 0;
}

9.逗号操作符

exp1,exp2,...,expN

逗号操作符将两个或多个表达式分隔开来。这些表达式自左向右逐个进行求值,整个逗号表达式的值就是最后那个表达式的值

int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);
	printf("a=%d b=%d\n",a,b);//12 13
	printf("%d\n",c);//13

	return 0;
}

10.下标引用,函数调用和结构成员

下标引用操作符:

[ ]:下标引用操作符,接受两个操作数:一个数组名和一个索引值

C语言的下标值总是从零开始,并且不会对下标值进行有效性检查。除了优先级不同之外,下标引用操作和间接访问表达式是等价的,像arr[4]==*(arr+4)==*(4+arr)

int main()
{
	int arr[10] = { 0 };
	arr[4] = 5;//就是下标引用操作符
	return 0;
}

函数调用操作符:

( ):函数调用操作符函数调用操作符接受一个或多个操作数。它的第一个操作数是你希望调用的函数名,剩余的操作数就是传递给函数的参数

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int ret = Add(2, 3);//()函数调用操作符,操作数就是:Add,2,3
	printf("%d\n",ret);

	return 0;
}

结构成员操作符:

.:结构体变量.成员名
->:结构体指针->成员名

如果s是个结构体变量,那么s.a就访问s中名叫a的成员。当你拥有一个指向结构的指针而不是结构本身,且欲访问它的成员时,就需要使用->操作符而不是.操作符

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

void print1(struct Stu ss)
{
	printf("%s %d %f\n",ss.name,ss.age,ss.score);
}

void print2(struct Stu* ps)
{
	//printf("%s %d %f\n",(*ps).name,(*ps).age,(*ps).score);
	printf("%s %d %f\n",ps->name,ps->age,ps->score);
}


int main()
{
	struct Stu s = {"张三",20,90};
	//s.name="张三丰"//name是数组名,代表的是数组首元素的地址
	strcpy(s.name,"张三丰");
	//print1(s);
	print2(&s);

	return 0;
}

表达式求值

表达式的求值顺序一部分是由它所包含的操作符的优先级和结合性决定

隐式类型转换

C语言的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符型和短整型操作数在使用之前被转换为普通类型,这种转换称为整型提升。

整型提升的意义:

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长
度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
换为int或unsigned int,然后才能送入CPU去执行运算。

在下面表达式的求值中,

char a,b,c;
a = b + c;

b和c的值被提升为普通整型,然后再执行加法运算。加法运算的结果将被截短,然后再存储于a中

如何进行整型提升?

整型提升是按照变量的数据类型的符号位来提升的

负数的整型提升:

char c1=-1;变量c1的二进制位(补码)中只有8个比特位:11111111。因为char为有符号的char,所以整型提升的时候,高位补充符号位,即为1。提升之后的结果是:11111111 11111111 11111111 11111111

正数的整型提升:

char c2=1;变量c2的二进制(补码)中只有8个比特位:00000001。因为char为有符号的char,所以整型提升的时候,高位补充符号位,即为0。提升之后的结果是:00000000 00000000 00000000 00000001

无符号整型提升:高位补0

案例一:

int main()
{
	//整型提升:是按照变量的数据类型的符号位来提升的
	char c1 = 3;//00000011->整型提升00000000 00000000 00000000 00000011
	char c2 = 127;//01111111->整型提升00000000 00000000 00000000 01111111
	char c3 = c1 + c2;//相加得:00000000 00000000 00000000 10000010,c3=10000010->整型提升11111111 11111111 11111111 10000010(补码)->原码10000000 0000000 0000000 01111110=-126

	printf("%d\n",c3);//-126

	return 0;
}

案例二:

int main()
{
	char a = 0xb6;//10110110,整型提升转换为负数
	short b = 0xb600;//10110110 00000000,整型提升转化为负数
	int c = 0xb6000000;

	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");//c

	return 0;
}

案例二中的a,b要进行整型提升,但是c不需要整型提升。a,b整型提升之后就变成了负数,所以表达式a == 0xb6,b == 0xb600的结果是假。但是c不发生整型提升,则表达式c == 0xb6000000的结果是真。

案例三:

int main()
{
	char c = 1;
	printf("%u\n",sizeof(c));//1
	printf("%u\n", sizeof(+c));//4,是表达式需要整型提升
	printf("%u\n", sizeof(-c));//4,是表达式需要整型提升
	return 0;
}

案例三中c只要参与表达式运算,就会发生整型提升,表达式+c就会发生提升,所以sizeof(+c)是4个字节;表达式-c也会发生整型提升,所以sizeof(-c)是4个字节,但是sizeof(c)就是1个字节.

算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另外一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换

long double
double 
float
unsigned long int
long int
unsigned int
int

如果某个操作数的类型在上面这个列标中排名较低,那么它首先将转换为另外一个操作数的类型然后执行操作。

操作符的属性

复杂表达式的求值顺序是由3个因素决定的:操作符的优先级,操作符的结合性以及操作符是否控制执行的顺序。

两个相邻的操作符哪个先执行取决于它们的优先级,如果两者的优先级相同,那么它们的执行顺序由它们的结合性决定。简单地说,结合性就是一串操作符是从左向右依次执行还是从右向左依次执行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何快速搭建SpringBoot+Vue前后端分离的开发环境

唠嗑部分 今天我们来说一说&#xff0c;如何快速搭建SpringBootVue前后端分离的开发环境 需要前置环境nodejs&#xff0c;请自行安装(傻瓜式安装) SpringBoot采用2.4.2版本&#xff0c;Vue采用Vue2版本 言归正传 创建Vue项目 1、安装vue npm install -g vue/cli2、检查v…

TDengine 报错 failed to connect to server, reason: Unable to establish connection

一、前文 TDengine 入门教程——导读 二、遇到问题 taos 命令行&#xff08;CLI&#xff09;连接不上&#xff0c;进不去。 [rootiZ2ze30dygwd6yh7gu6lskZ ~]# taos Welcome to the TDengine Command Line Interface, Client Version:3.0.0.1 Copyright (c) 2022 by TDengine…

Linux 安装nodejs、npm、yarn、nrm(超实用)

前言&#xff1a;初衷想要本地通过dockerfile文件直接把项目打包到linux服务器&#xff0c;不用再本地加载再上传等&#xff0c;后续再贴上配置文件 一、什么是nodejs 来自官网的介绍&#xff0c;Node.js 是一个开源的跨平台 JavaScript 运行时环境。它几乎是任何类型项目的流…

JVM内存结构介绍

我们都知道&#xff0c;Java代码是要运行在虚拟机上的&#xff0c;而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域&#xff0c;这些区域都有各自的用途。其中有些区域随着虚拟机进程的启动而存在&#xff0c;而有些区域则依赖用户线程的启动和结束…

远程访问群晖Drive并挂载为电脑磁盘同步备份文件「无需公网IP」

文章目录 前言视频教程1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 转发自CSDN远程穿透的文章&…

【Netty】Reactor 模型(十)

文章目录 前言一、传统服务的设计模型二、NIO 分发模型三、Reactor 模型3.1、Reactor 处理请求的流程3.2、Reactor 三种角色 四、单Reactor 单线程模型4.1、消息处理流程4.2、缺点 五、单Reactor 多线程模型5.1、消息处理流程5.2、缺点 六、主从Reactor 多线程模型6.1、Reactor…

【How to Design Translation Prompts for ChatGPT: An Empirical Study 论文略读】

How to Design Translation Prompts for ChatGPT: An Empirical Study 论文略读 INFORMATIONAbstract1 Introduction2 Background3 Experiments3.1 Prompt Design3.2 Experimental Setup3.2.1 Datasets3.2.2 Baselines and Evaluation Metrics 3.3 Multilingual Translation3.4…

Vue实现订单确认界面禁止浏览器返回操作导致重复提交订单的问题

哈喽 大家好啊 最近遇到一个问题&#xff0c;就是在提交订单成功后的页面&#xff0c;然后用户去浏览器返回&#xff0c;就导致又提交了一次 然后就想到了如果提交成功页面&#xff0c;就阻止浏览器返回操作 主要实现如下&#xff1a; 1.在mounted的钩子函数&#xff1a; 2.…

论文阅读:GLOBAL PROTOTYPE ENCODING FOR INCREMENTALVIDEO HIGHLIGHTS DETECTION

摘要&#xff1a; 视频亮点检测 (VHD) 是计算机视觉中的一个活跃研究领域&#xff0c;旨在在给定原始视频输入的情况下定位最吸引用户的片段。然而&#xff0c;大多数 VHD 方法都是基于封闭世界假设&#xff0c;即预先定义固定数量的高亮类别&#xff0c;并且所有训练数据都是…

4.Ansible Inventory介绍及实战 - A list or group of lists nodes

什么是inventory&#xff1f; 官方解释&#xff1a;Ansible automates tasks on managed nodes or “hosts” in your infrastructure, using a list or group of lists known as inventory. Ansible可以同时与您基础设施中的一个或多个系统协同工作&#xff61;为了与多台服务…

RPC核心原理(整体架构/调用过程)

Server: Provider ,暴露服务,服务提供方 Client: Consumer ,服务消费,调用远程服务 Registry:服务注册与发现 RPC的调用过程如下&#xff1a; 第一步&#xff1a;server会将他需要暴露的服务以及他的地址信息注册到Registry这一注册中心。 第二步&#xff1a;client通过注册…

【分布鲁棒和多目标非负矩阵分解】基于DR-NMF的对NMF问题噪声模型的识别鲁棒性研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Doris的一些进阶用法

6.doris进阶 6.1修改表 6.1.1修改表名 示例&#xff1a; 将名为 table1 的表修改为 table2 SQLALTER TABLE table1 RENAME table2; -- 示例 ALTER TABLE aggregate_test RENAME aggregate_test1; 将表 example_table 中名为 rollup1 的 rollup index 修改为 rollup2 SQLA…

Ex-ChatGPT本地部署+Azure OpenAI接口配置+docker部署服务

Ex-ChatGPT项目分为 Ex-ChatGPT 和 WebChatGPTEnhance 两部分&#xff0c;Ex-ChatGPT启动后是个web服务&#xff0c;通过访问ip端口体验&#xff1b; WebChatGPTEnhance可编译生成一个浏览器插件&#xff0c;Chrome或者Microsoft edge浏览器可以安装该插件&#xff0c;点击该插…

【MySQL】如何实现单表查询?

在我们对数据进行操作时&#xff0c;查询无疑是至关重要的&#xff0c;查询操作灵活多变&#xff0c;我们可以根据开发的需求&#xff0c;设计高效的查询操作&#xff0c;把数据库中存储的数据展示给用户。 文章目录 前言1. 基础查询1.1 基础查询语法1.2 基础查询练习 2. 条件查…

数据库基础——5.运算符

这篇文章我们来讲一下SQL语句中的运算符操作。 说点题外话&#xff1a;SQL本质上也是一种计算机语言&#xff0c;和C&#xff0c;java一样的&#xff0c;只不过SQL是用来操作数据库的。在C&#xff0c;java中也有运算符&#xff0c;这两种语言中的运算符和数学中的运算符差距不…

crontab定时任务介绍

1 crontab概述 crontab是linux操作系统上用来设置定时任务的基础命令&#xff0c;是基于crond服务实现任务调度执行。 当安装完成操作系统后&#xff0c;默认会安装crond服务及其附属命令&#xff0c;并且会自动启动crond进程&#xff0c;crond进程每分钟会定期检查是否有要执…

还在用 JS 做节流吗?CSS 也可以防止按钮重复点击

目录 一、CSS 实现思路分析 二、CSS 动画的精准控制 三、CSS 实现的其他思路 四、总结一下 众所周知&#xff0c;函数节流&#xff08;throttle&#xff09;是 JS 中一个非常常见的优化手段&#xff0c;可以有效的避免函数过于频繁的执行。 举个例子&#xff1a;一个保存按…

11.PasswordEncoder详解与实战

security/day07 这节课我们开始讲PasswordEncoder&#xff0c;如果大家还有印象的话&#xff0c;我们前面有提到过PasswordEncoder: 为什么密码使用{noop}开头呢&#xff1f;我们也做出了相应的解释&#xff0c;这节课开始带大家真正的了解PasswordEncoder, PassworderEncoder…

哈夫曼树(Huffman)【数据结构】

目录 ​编辑 一、基本概念 二、哈夫曼树的构造算法 三、哈夫曼编码 假如<60分的同学占5%&#xff0c;60到70分的占15%…… 这里的百分数就是权。 此时&#xff0c;效率最高&#xff08;判断次数最少&#xff09;的树就是哈夫曼树。 一、基本概念 权&#xff08;we…