5.17笔记(操作符)

1. 算术操作符

 + - * / %

注意:

  1. %的操作符的两个操作数都必须为整数。
  2. 其余几个操作符皆可用于整数和浮点数。
  3. 对于/操作符,如果两个数都是整数,则执行整数除法,若有一个为浮点数,则执行浮点数除法。

2.移位操作符

  1. 逻辑移位:二进制位上进行左移右移,两头用0进行补充,不用关心符号位的问题。
  2. 算术移位:二进制位上进行左移右移,两头用0进行补充,但必须保证其符号位不变。

介绍4个汇编中的指令:
SHL:逻辑左移
SHR:逻辑右移
SAL:算术左移
SAR:算术右移

int main()
{
	char i = 128;
	i = i >> 3;
	printf("%d\n", i);
	return 0;
}

上述代码块究竟采用的是逻辑右移呢还是算术右移?

1. 有符号整型正数左移

int main()
{
	int i = 1;
	i = i << 3;
	return 0;
}

我这里采用的是vs2017,打开反汇编窗口:
在这里插入图片描述
采用的为逻辑左移。

2. 无符号整型正数左移

int main()
{
	unsigned int i = 1;
	i = i << 3;
	return 0;
}

在这里插入图片描述
采用的为逻辑左移。

3. 有符号整型负数左移

int main()
{
	int i = -1;
	i = i << 3;
	return 0;
}

在这里插入图片描述
采用的为逻辑左移。

4. 无符号整型负数左移

int main()
{
	unsigned int i = -1;
	i = i << 3;
	return 0;
}

在这里插入图片描述
采用的为逻辑左移。
结论:无论有无符号类型,正数负数,左移时均为逻辑左移。

5. 有符号整型正数右移

int main()
{
	int i = 1;
	i = i >> 3;
	return 0;
}

在这里插入图片描述
采用的算术右移。

6. 无符号整形正数右移

int main()
{
	unsigned int i = 1;
	i = i >> 3;
	return 0;
}

在这里插入图片描述
采用的为逻辑右移。
7. 有符号整型负数右移

int main()
{
	int i = -1;
	i = i >> 3;
	return 0;

在这里插入图片描述
采用的为算术右移。
8. 无符号整型负数右移

int main()
{
	unsigned int i = -1;
	i = i >> 3;
	return 0;
}

在这里插入图片描述
采用的为逻辑右移。
结论:有符号数,在右移时采用算术右移;无符号数,在右移时采用逻辑右移。
 
 
 
 
 
注意:在这种情况下,虽然为无符号数,但是最高位为1,被当成了有符号数,采用的为算术右移,但右移时,左边补0。

int main()
{
	unsigned char i = 128;
	i = i >> 3;
	printf("%d", i);
	return 0;
}

在这里插入图片描述
结果为:
在这里插入图片描述
为什么左移全部是逻辑左移呢?
答:先了解不同数在二进制中的存储方式。
正数按照原二进制存储。如3,在计算机中存储为:0x3;
负数按照其补码方式在计算机中存储,如-3,在计算机中存储为0xfffffffb。

计算机以补码的形式存储负数。有无符号数在左移时,均不会改变其符号位,故采用的均为逻辑左移;但在右移时,无符号数右移不会改变其符号位,有符号数必须保证其符号位保持不变,故只能采取算术右移。

左移相当于乘2
右移相当于除2
左移右移不会改变其本身的值
直接移位比乘除好,更快一点

3.位操作符

& //按位与
| //按位或
^ //按位异或
他们的操作数必须为整数。

一道比较有意思的题:求一个整数存储在内存中的二进制1的个数?

  1. 一般的思路是,做循环,将该数挨个右移,并和1&,计数。这里面的做法必须循环32次,可以进行优化。先附这样的代码:
int main()
{
	int num = 99;
	int i = 0;
	int count = 0;//计数
	for (; i < 32; i++)
	{
		if (1 == ((num >> i) & 1))
		{
			count++;
		}
	}
	printf("%d\n", count);
	return 0;
}

2.另一个种比较难想的思路:做循环,令该数等于该数&该数减1。
第一次:计数+1
在这里插入图片描述
第二次:计数+1
在这里插入图片描述
第三次:计数+1
在这里插入图片描述
第四次:计数+1
在这里插入图片描述

最后该数为0,循环停止,该数二进制总共有4个1。
附代码:

int main()
{
	int num = 99;
	int count = 0;//计数
	while (num)
	{
		count++;
		num = num & (num - 1);
	}
	printf("%d\n", count);
	return 0;
}

结果为:
在这里插入图片描述

4.赋值操作符

  1. 复合操作符

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

注:这样的连等式子都是从右向左看。
如:

int main()
{
	int a = 3;
	int i = 10;
	int j = 20;
	a *= i + j;
	printf("%d\n", a);
	return 0;
}

输出结果为:90。
 

5.单目操作符

!                                逻辑反操作
-                            
+
&                                 取地址
sizeof                            操作数的类型长度(字节为单位)(不是函数)
~                                 按二进制位进行取反
- -
++
 *
(类型)                           强制类型转换

笔记:任何一个变量都可以站在3个角度去理解:变量空间、变量内容、变量地址
强转改变的是我们看待数据的方式。
类型决定了:变量的意义,看待的方式,开辟了多大的空间

6.关系操作符

>
>=
<=
!=
==

7.逻辑操作符

&&
||

 
 
 
注意:
逻辑与:前半部分不成立,则不用运行后边的。
逻辑或:前半部分成立,则不用运行后边的。

 
 
 
8.条件操作符

也叫做三目运算符

a>b?a:b,意思为如果a大于b,则输出a,否则输出b。
 
 
 
9.逗号表达式

在逗号表达式中,会依次执行逗号中的内容,并将最后一个表达式作为该式子的值。

int main()
{
	int b = (1, 2, 3, 4, 5, 6, 7, 8);
	printf("%d\n", b);
	return 0;
}

最后结果为:b=8。

 
 
 
 
 
 
操作符的优先级和结合性。
一般不要写特别复杂的表达式。

隐式类型转换:

为什么要整型提升?
因为表达式的运算是在CPU的的相应运算器件中执行的,CPU整型运算器(ALU)的操作数的字节长度一般是int的字节长度,同时也是CPU的通用寄存器长度。

如何进行整型提升?
整型提升是按照变量的数据类型的符号位来提升的。

①如果为无符号数:整型提升直接全部补0。
②如果为有符号数:补符号位(看变量的类型)。
一个数为char类型,与操作符进行运算时就会发生整型提升。

猜你喜欢

转载自blog.csdn.net/w903414/article/details/106174493