计算机底层知识:二进制&内存 原码 反码 补码

198 阅读7分钟

1.机器语言

和计算机直接交流的语言,就是机器语言,而计算机只能通过硅晶体的单项导电性表示出两种状态,我们把这两种状态标为0和1,所以计算机只认识0和1,那么0和1也就是机器语言,早期的穿孔卡带,摩斯密码都是用这种方式来传播的信息


2.助记符

因为计算机只认识0和1,所以我们在表示运算符的时候,只能通过0010 1100这样的方式表示某个符号,十分麻烦,也很难记住,于是就有了助记符

加 INC -编译器-> 0010 1100
减 DEC
乘 MUL
除 DIV

用助记符可以方便我们记住加减乘除以及其他符号,不用直接写0和1

而这样子还是很难习惯,我们大多都习惯用符号表示运算符 所以在高级语言中,又再次做了处理

加 A+B -编译器-> 0010 1100
减 A-B 
乘 A*B 
除 A/B 

3.进制

3.1.进制的概念

定义:是人们规定的一种进位方法,用于计数的方式

0,1,2,3,4,5,6,7,8,9 只是发明十进制的人用于计数定义的符号

所以,你也可以自己定义一种进制的方式

比如,我们定义一个进制,符号用3,9,2,a,b来表示 那么如下,就是这个进制中从1 - 15的计数

3,9,2,a,b

93,99,92,9a,9b

23,29,22,2a,2b

3.2.常用的进制

1进制:一进一,结绳记事。1 1
2进制:二进一,计算机
8进制:八进一,8个符号组成:0 1 2 3 4 5 6 7
10进制:十进一,10个符号组成:0 1 2 3 4 5 6 7 8 9
16进制:十六进一,16个符号组成:0 1 2 3 4 5 6 7 8 9 a b c d e f

3.3.进制的计算

以八进制为例:

6 + 7 = 15
6 - 7 = 6 + (-7) = -1
6 * 7 = 6 + 6 + 6 + 6 + 6 + 6 + 6 =  52

除法的本质是除数乘以哪个数最接近结果
以52 / 7 为例
52 / 7  
	= 要做的是算出52中有几个7(要注意这时候的 7+1=10 而不是8) 
	= 52-7-7-7-7-7-7(到第7个7时,会小于0,所以只能减6次7,那么结果就是6)
  	= 6
可以把每个-7换算位+(-7)

结论:加减乘除的本质,都是加法


4.内存

4.1.内存大小转换

1GB=1024MB 1MB=1024KB 1KB=1024B 1B(1字节)=8bit(位) 1位(bit)只能存储一个0或1,同时也是计算机最小的存储单位


4.2.内存宽度

在内存中,每个数据都是有宽度的,所谓宽度,就是这个数据需要占用几个字节

用四个位就可以表示 0 - 1111之间的数字,共16个
0 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111

这样写我们很容易记不住,所以可以用16个符号来表示这16个二进制,也就是我们的16进制
0 1 2 3 4 5 6 7 8 9 a b c d e f

有了以上概念作为支撑,我们就可以得出以下结论

4位 = F

1字节 = 8位 = FF

byte = 		1字节 = 	8位 	= FF
char = 		2字节 = 	16位 	= FFFF
int  = 		4字节 = 	32位 	= FFFFFFFF
long = 		8字节 = 	64位 	= FFFFFFFFFFFFFFFF

所以在高级语言中,声明变量的动作 本质上就是给数据指定宽度


5.二进制

5.1.有符号数 or 无符号数

概念:在计算机中,所有东西都是0和1,那么是不存在负数的,所以我们想要表示负数,就要给计算机制定一个规则,也就是制定符号位

我们看到一个二进制数字,得先知道它是有符号数还是无符号数

无符号数规则

这数字是什么 就是什么。
1111 1111 十六进制:0xFF 十进制 255

有符号数规则

最高位是符号位:1 (负数) 0(正数)
1111 1111 十六进制:0xFF 十进制 -1

5.2. 原码 反码 补码

原码: 最高位符号位,对其他位取绝对值。

反码: 正数:反码和原码相同 负数:符号位一定是1,其余位对原码取反。

补码: 正数:补码和原码相同 负数:符号位一定是1,反码+1

简单来说,这三个东西对于正数都是一样的,对于负数,也只用关心补码,补码就是把除了符号位以外所有位取反 然后+1

为什么有补码? 因为我们制定的规则是用0和1区分符号 + 和 - ,可是这样的区分方法计算机是无法用这个数字做运算的 计算机的做法是对半分,比如8位可以存0-255,那么在有符号的情况下,计算机会从0开始正着数128位作为正数,从-1开始倒着数127位作为负数,这样一来,负数就可以做运算了 那么补码就是为了把我们定义的负数形式,转为计算机可以做运算的负数形式,做法就是反码+1,也就是我们说的补码。


5.3. 位运算

概念:位运算是计算机中最高效率的运算方式,所有的加减乘除底层都是位运算来完成的


5.3.1.与运算(and &)

两个都为1,结果为1 在这里插入图片描述

1011 0001
1101 1000
----------- 与运算。
1001 0000

5.3.2.或运算(or |)

只要有一个为1,结果为1 在这里插入图片描述

1011 0001
1101 1000
----------- 或运算
1111 1001

5.3.3.异或运算(xor ^)

不一样就是1 在这里插入图片描述

1011 0001
1101 1000
----------- 异或运算
0110 1001

5.3.4.非运算(单目运算符 not ~)

0就是1,1就是0 ,取反

1101 1000
----------
0010 0111

5.3.5.位运算(移动位)

左移:(shl <<) 所有二进制位全部左移若干位,高位就丢弃了,低位补0

0000 0001 
0000 0010

右移:(shr >>) 所有二进制位全部右移若干位,低位就丢弃了,高位就需要补0,1(符号位决定。)

0000 0001 
0000 0000
int a = 10;
printf("%d\n",a>>2);

5.4.位运算加减乘除

因为计算机只认识0和1,所以计算机中的所有加减乘除都是用位运算来完成的 而加减乘除的本质都是加法

4+5

# 第一步:异或: 如果没有进位,异或就可以直接出结果。
0000 0100
0000 0101
------------
0000 0001

# 第二步:与运算(判断进位,如果与运算结果为0,没有进位。)
0000 0100
0000 0101
------------
0000 0100

# 第三步:将与运算的结果,左移一位。 
0000 1000 

# 第四步:把开始异或的结果和进位的结果再次就行异或
0000 0001
0000 1000
-------------
0000 1001

# 第五步:与运算(判断进位,如果与运算结果为0,没有进位。)
0000 0001
0000 1000
-----------
0000 0000

# 所以最终的结果就是与运算为0的结果的上一个异或运算。