1.操作符分类
1.算数操作符
+ - * / %
- 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
- 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
- % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
例如:
int a=5; int b=4; int c=5/3 --结果为1 除法结果为取商 // int c=5/3.0 -- 此时,由于除号两边有一边为浮点数,那么结果就为浮点 // 型-- 1.25 int d=a%b; -- 商 1 余1 因此 d= 1 // 取模的结果是余数,且取模符号 %两边都只能是整形 注意: d的结果一定是再 0<=d<b 的 若 int d=a%b +1 ,则结果为1~b 之间
2.位移操作符
<< 左移操作符 >> 右移操作符
对于位移操作符,操作对象为二进制位的补码并且只能是整数
1. << 左移操作符:左边丢弃,右边补0
例如:
int a=5;
正整数原码 反码 补码相同–再内存中存储的为补码
00000000000000000000000000000101 – a的补码
此时 a<<1 意味将a向左移动 1 位
2.右移操作符:右移操作符相比左移操作符规则上有所不同
分为两种: 1.逻辑位移:左边用0填充,右边丢弃 2.算数位移:左边用原该值的符号位(最高位)填充,右边丢弃
例如:
int a=5
a再内存中存储的是补码
00000000000000000000000000000101 --补码
a>>1
若为逻辑位移
若为算数位移:
对于正数而言,最高位符号位位0,算数位移和逻辑位移结果一致。
若为负数,int a= -5;再内存中为补码
10000000000000000000000000000101–原码
符号位(最高位不变)其他位按位取反(1为0,0为1)
111111111111111111111111111111111010–反码
反码加1为补码
111111111111111111111111111111111110–补码
若为逻辑位移
a>>1
若为算数位移:
111111111111111111111111111111111110-- -1 的补码
不难发现:正数的逻辑位移和算数位移是结果相同的,但是负数的逻辑位移和算数位移不一样,应当注意。
那么对于负数的右移到底是算数位移还是逻辑位移呢?
在不同的编译器上采取的处理方式不一样,为其中的一种,但多数都是算数位移
3.位操作符
& //按位与 | //按位或 ^ //按位异或
注意:它们之间操作的都是整数且操作的是二进制位的补码
1. 按位与(&)
运算规则:两个整数对应的二进制位同时为1,结果才为1,否则为0。
int a=5;
int b=1;
int c=a&b; c的结果是多少呢?
a再内存中存储的是二进制补码
a&b: 00000000000000000000000000000101 -- a 补码 00000000000000000000000000000001 -- b 补码
有一个0则为0,只有同为1才为1
00000000000000000000000000000001 -- c 的补码 由于正整数的原码 反码 补码相同,打印时打印的是原码的结果 因此 c 结果为5
对于含负数的按位或:
int a=5;
int b=-2;
int c=a&b;
00000000000000000000000000000101 -- a 补码 10000000000000000000000000000010 -- b 原码 11111111111111111111111111111101 -- b 反码 11111111111111111111111111111110 -- b 补码
a&b:
00000000000000000000000000000101 -- a 补码 11111111111111111111111111111110 -- b 补码
有一个0则为0,只有同为1才为1
00000000000000000000000000000100 -- c 的补码 由于打印时打印的是原码,因此 c 结果为 4
在这你有没有发现 一个正整数& 1 结果为它本身?
那么 我们就可以通过前面的位移操作符和 按位与结合,获取一个整数二进制中的每一位数
例如:获取 5 二进制中的每一位数
for(int i;i<32;i++); { int c=(5>>i)&1; }
2.按位或( | )
运算规则:两个整数对应的二进制位有一个1则为1,只有同为0才为0
int a=5;
int b=2;
int c=a&b; c的结果是多少呢?
a | b: 00000000000000000000000000000101 -- a 补码 00000000000000000000000000000010 -- b 补码
有一个1则为1,只有同为0才为0
00000000000000000000000000000111 -- c 补码
打印时,打印的是原码,因此 c 的 结果为 7
对于含负数的按位或:
int a=5;
int b=-2;
int c=a|b;
00000000000000000000000000000101 -- a 补码 10000000000000000000000000000010 -- b 原码 11111111111111111111111111111101 -- b 反码 11111111111111111111111111111110 -- b 补码
a|b:
00000000000000000000000000000101 -- a 补码 11111111111111111111111111111110 -- b 补码
有一个1则为1,只有同为0才为0
11111111111111111111111111111111 -- c 补码
打印时,打印的是原码,因此负数的补码还需要还原为原码
11111111111111111111111111111111 -- c 补码 补码-1 得到反码 11111111111111111111111111111110 -- c 反码 反码符号位不变,其余按位取反 10000000000000000000000000000001 -- c 原码 所以 c 的结果为 -1
3.按位异或(^)
运算规则:两个整数对应的二进制位相同,则结果为0,否则为1
int a=5;
int b=3;
int c=a^b;
000000000000000000000000000000101 -- a 补码 000000000000000000000000000000011 -- b 补码
a^b:
000000000000000000000000000000101 -- a 补码 000000000000000000000000000000011 -- b 补码
相同为0,相异为1
00000000000000000000000000000110 -- c 原码 打印c 的结果为 6
对于含负数的按位与:
int a=5;
int b= -3;
int c=a^b;
000000000000000000000000000000101 -- a 补码 100000000000000000000000000000011 -- b 原码 111111111111111111111111111111100 -- b 反码 111111111111111111111111111111101 -- b 补码
a^b:
000000000000000000000000000000101 -- a 补码 111111111111111111111111111111101 -- b 补码
相同为0,相异为1
111111111111111111111111111111000 -- c 补码 打印出 c 的结果为 -8
对于按位异或,我们可以从下面的代码发现如下规律:
0^0 = 0; 1^0 = 1; //0异或一个数 = 这个数 0^1 = 1; //异或具有交换律 1^1 = 0;//自己异或自己 = 把自己置为0
再看一道经典例题:
实现两个值的交换,而不必使用临时变量。 例如交换两个整数a=5,b=3的值,可通过下列语句实现: a = a^b; // b = b^a; //b=a^b^b = a^0 = a a = a^b; //a=a^b^^a = a^a^b = 0^b = b
利用我们上面的规则,很容易就将两个数交换值,并且这样不会存在溢出的问题
其次,还可以利用按位与快速判断两个整数是否相等
int a=5; int b=4; if(a^b==0) //根据我们上述发现的规律可以知道 //如果a b相等,那么 a^b一定为0 a=1; else a=2;
4.复合操作符
+= -= *= /= %= >>= < <= &= |= ^=
对于上述操作符,都是由两个操作符复合组成的,那应该如何理解呢?
例如: +=,就是加上一个数后 = 什么
int a=2;
a+=2 // a先加再赋值,最后a变成了4;
同理 a-=2;//此时a先减,最后再赋值变成里 0
后面的 *= /= >>= … 均是如此。