目录
二进制表达式:
在二进制系统中,每一位(binary digit, 或简称 bit)的值只能是0或1。而在计算机中常见的一些基本数据类型的二进制原码基于下述几种编码方法:
①无符号整数:
无符号整数的二进制表示非常直观:它们直接映射到它们的二进制等效物。比如,无符号8位整数(uint8_t)的二进制原码范围从00000000(即十进制的0)到11111111(即十进制的255)。
②有符号整数:
有符号整数涉及到表示负数。在C++中,默认使用补码(twos-complement)表示法来表示有符号整数。
-
- 正数的补码与其无符号的表示相同。
- 负数的补码是其绝对值的二进制表示的按位取反后加一。
- 有符号整数的二进制原码的最高位代表符号位,为1,则为负数,为0则为非负数。
例如,有符号8位整数(int8_t)的补码表示法中:十进制的-1在内存中会被编码为11111111,而十进制的-128会被编码为10000000
③原码与补码
原码是二进制编码方式的一种,用来表达有符号的整数,其最高位(最左边的位)作为符号位:0表示正数,1表示负数,其余位代表该数的绝对值。
对于原码表达方式:
- 正数的原码表示法很直接,就是其绝对值的普通二进制表示,加上最左边的一个零。
- 负数的原码按照正数的原码表示其绝对值,只是将最左边的符号位改为1。
举例来说,用一个8位的有符号整数来表达:
```
+5 的原码为 0000 0101
-5 的原码为 1000 0101 (最高位为1,表示负数)
```
然而,原码的缺点在于它会导致有两个零的编码(正0和负0),并且不能直接进行加减运算。
补码是计算机中最常用的数字表示方式。它解决了原码的缺点,使得加减运算得以简化,也消除了双零问题。补码规则如下:
- 正数的补码与其原码相同。
- 负数的补码是其原码的位反(除了最高位,其他位取反,1变0,0变1)后加一。
-无符号数的原码和补码相同。
以8位二进制为例:
```
+5 的补码为 0000 0101 (与原码相同)
-5 的正数原码为 0000 0101, 取反得到 1111 1010, 加一得到 1111 1011,这就是-5的补码。
```
补码系统的特殊之处在于最大的负数(例如在8位中是1000 0000)没有对应的正数,因为该值的补码表示还是它自己(即-128在8位补码系统中没有对应的+128)。并且在补码系统中,两个数值的加法运算是无差别的,不论它们的符号如何。
在进行位运算时,应使用补码进行操作。例如,如果你使用二进制左移的运算,你会将补码形式的数字向左移动相应的位数。这是因为计算机内部使用补码进行计算,且位运算符(如 <<,>>)都是直接在这些补码上操作的。
总的来说,原码和补码是两种不同的二进制编码方式,其中补码因其便于运算的特性而在计算机系统中被广泛使用。
位运算:
位运算读法与符号:非~,左移<<,右移>>,与&,异或^,或|
这里按照计算顺序的优先级,从左往右列举。
任何位运算都是直接针对二进制表达式进行的操作。
①非~:0变1,1变0
非运算即按位取反
在有符号int类型下,以1为例,1的补码是0000,0000,0000,0000,0000,0000,0000,0001
则~1=~0000,0000,0000,0000,0000,0000,0000,0001=1111,1111,1111,1111,1111,1111,1111,1110
(这里显示细节,实际操作中不会显式出现二进制位)
在有符号的int类型下,1111,1111,1111,1111,1111,1111,1111,1110代表的数是-2
可以说在有符号的任何类型下~n=-(n+1),这个式子揭示有符号类型下的非操作之后的数值结果。
在无符号类型下,非操作之后的数值结果就是二进制表达式所对应的十进制数。
在无符号类型下,1111,1111,1111,1111,1111,1111,1111,1110=18446744073709551614
②左移<<:把二进制表达式整体向左平移,溢位弃,缺位补
a<<b,代表把a向左移动b个位,并且在缺失的位上补0,例:
0000,0000,0000,0000,0000,0000,0000,0001<<3=0000,0000,0000,0000,0000,0000,0000,1000
1000,1000,1000,1000,1000,1000,1000,1000<<1=0001,0001,0001,0001,0001,0001,0001,0000
在不会溢出的情况下,一般情况下左移操作在数值上等于原数乘2的幂,即a<<b=a*(2的b次方)
③右移>>:把二进制表达式整体向右平移,溢位弃,缺位补
a>>b,代表把a向右移动b个位,注意,如果是无符号整数,缺失的位上依旧是补0,
但是在有符号整数上,右移时,最高位会补上该数对应的符号位的数,例:
0000,0000,0000,0000,0000,0000,0000,1000>>3=0000,0000,0000,0000,0000,0000,0000,0001
如果是无符号整数:
1000,1000,1000,1000,1000,1000,1000,1000>>1=0100,0100,0100,0100,0100,0100,0100,0100
如果是有符号整数:
1000,1000,1000,1000,1000,1000,1000,1000>>1=1100,0100,0100,0100,0100,0100,0100,0100
1000,1000,1000,1000,1000,1000,1000,1000>>2=1110,0010,0010,0010,0010,0010,0010,0010
右移操作不会导致数据溢出,一般情况下在数值上等于原数整除2的幂,即a>>b=a/(2的b次方)
特殊的,-1>>a=-1,(a>0)
④与&:有0则0,全1则1
0 1 1
& 0 & 0 & 1
——— ——— ———
= 0 = 0 = 1
⑤异或^:同则0,异则1
0 1 1
^ 0 ^ 0 ^ 1
——— ——— ———
= 0 = 1 = 0
⑥或|:有1则1,全0则0
0 1 1
| 0 | 0 | 1
——— ——— ———
= 0 = 1 = 1