操作符—关于二进制的操作符
一.原码、反码、补码
众所周知,在计算机中是通过二进制进行存储的。
整数的2进制表示方法有三种,即原码、反码和补码
有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,最⾼位的1位是被当做符号位,剩余的都是数值位。
符号位都是⽤0表示“正”,⽤1表示“负”。
正整数的原、反、补码都相同。
负整数的三种表示方法各不相同。
对于负整数:
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码。
补码得到原码也是可以使⽤:取反,+1的操作
对于整形来说:数据存放内存中其实存放的是补码。
例如: 5和-4的原码、反码、补码
//5和-4的原码、反码、补码
//5
00000000 00000000 00000000 00000101 原码
00000000 00000000 00000000 00000101 反码
00000000 00000000 00000000 00000101 补码
//-4
10000000 00000000 00000000 00000100 原码
11111111 11111111 11111111 11111011 反码
11111111 11111111 11111111 11111100 补码
补充:为什么呢?
在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀
处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
二.移位操作符
1.<< 左移操作符
2.>> 右移操作符
注:移位操作符的操作数只能是整数。
1.左移操作符(<<)
移位规则:左边抛弃、右边补0
#include <stdio.h>
int main()
{
int num = 10;
int n = num<<1;
printf("n= %d\n", n);
printf("num= %d\n", num);
return 0;
}
结果:
原理:
//num=10
00000000 00000000 00000000 00001010 --原码反码补码
//n=?=20
00000000 00000000 00000000 00010100 --原码反码补码
2.>>右移运算符
移位规则:⾸先右移运算分两种:
-
逻辑右移:左边⽤0填充,右边丢弃
-
算术右移:左边⽤原该值的符号位填充,右边丢弃
在VS2022调试中,使用负整数来判断是哪一种运算:
#include<stdio.h>
int main()
{
int num = -20;
int n = num >> 1;
printf("n=%d\n", n);
printf("num=%d\n", num);
return 0;
}
结果:
所以,在VS2022中,使用的是算术右移
三.位操作符
1.&按位与
运算规则:只有两个数的二进制同时为1,结果才为1,否则为0
1.1.两个正整数:
#include<stdio.h>
//& 5 6
int main()
{
int x = 5;
int y = 6;
int ret = x & y;
printf("%d", ret);
return 0;
}
结果:
原理:
//& 5 6 ret=5&6
运算规则:只有两个数的二进制同时为1,结果才为1,否则为0
00000000 00000000 00000000 00000101 --5的原码反码补码
00000000 00000000 00000000 00000110 --6的原码反码补码
00000000 00000000 00000000 00000100 --ret的原码反码补码
一个正整数和一个负整数:
#include<stdio.h>
//& -5 6
int main()
{
int x = -5;
int y = 6;
int ret = x & y;
printf("%d", ret);
return 0;
}
结果:
原理:
//& -5 6 ret=-5&6
1000000 00000000 00000000 00000101 -- -5的原码
1111111 11111111 11111111 11111010 -- -5的反码
1111111 11111111 11111111 11111011 -- -5的补码
0000000 00000000 00000000 00000110 -- 6的原码反码 补码
0000000 00000000 00000000 00000010 -- ret的补码
因为ret的补码是个正数,所以ret的原码反码补码都一样
2.|按位或
运算规则:参加运算的两个数只要两个数中的一个为1,结果就为1。
一个正数和负数:
#include<stdio.h>
//| -5 6
int main()
{
int x = -5;
int y = 6;
int ret = x | y;
printf("%d", ret);
return 0;
}
结果:
原理:
//| -5 6 ret=-5 | 6
运算规则:参加运算的两个数只要两个数中的一个为1,结果就为1。
1000000 00000000 00000000 00000101 -- -5的原码
1111111 11111111 11111111 11111010 -- -5的反码
1111111 11111111 11111111 11111011 -- -5的补码
0000000 00000000 00000000 00000110 -- 6的原码反码 补码
1111111 11111111 11111111 11111111 -- ret的补码
1000000 00000000 00000000 00000000 +1
1000000 00000000 00000000 000000001 -- ret的原码
3.^按位异或
一个正数一个负数
运算规则:参加运算的两个数,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
#include<stdio.h>
// ^ -5 6
int main()
{
int x = -5;
int y = 6;
int ret = x ^ y;
printf("%d", ret);
return 0;
}
结果:
原理:
^ -5 6 ret=-5 ^ 6
// 运算规则:参加运算的两个数,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
1000000 00000000 00000000 00000101 -- -5的原码
1111111 11111111 11111111 11111010 -- -5的反码
1111111 11111111 11111111 11111011 -- -5的补码
0000000 00000000 00000000 00000110 -- 6的原码反码 补码
1111111 11111111 11111111 11111101 -- ret的补码
1000000 00000000 00000000 00000010 +1
1000000 00000000 00000000 00000011 -- ret的原码
4.~按位取反
运算规则:将一个数的二进制表达的每一位取反,即0变为1,1变为0。取反符号用 “~” 表示。(从最低位(最右侧位)开始,逐位进行取反操作
负数:
#include<stdio.h>
//~ -5 ret=~(-5)
int main()
{
int x = -5;
int ret = ~x;
printf("%d", ret);
return 0;
}
结果:
原理:
//~ -5 ret=~(-5)
1000000 00000000 00000000 00000101 -- -5的原码
1111111 11111111 11111111 11111010 -- -5的反码
1111111 11111111 11111111 11111011 -- -5的补码
0000000 00000000 00000000 00000100 -- ret的原码反码补码
5.规律:
(1)异或,相同为0,相异为1
(2)a^a=0(任何数和它本身异或结果为0)
(3)a^0=a (任何数与0异或结果还是它本身)
(4)异或支持交换律
关于位操作符的运用,请听下回分解!
如果有想要C语言资料的人,请私聊v:xwzj050125