整数的二进制表示有3种,分别为原码,反码和补码,而整数在内存中的是补码。
????????其中正整数的原码,反码和补码都是相同的。
????????而负整数的原码,反码和补码都是需要计算的。
相关移位操作符请见:
左移操作符就是将整型补码向左进行移位。下列以数字7和-7为例。
int a = 7;
int b = a << 1;
printf("%d\n", a);
printf("%d\n", b);
????????将整型 7 的二进制转换以后为 111,整型在内存当中占4个字节,一个字节占8bit,因此,整型 7的原码为32个bit单位。
????????原码由该二进制数左端向左补零,直到补满32位数字,而第一位数字为符号位(0为整数,1为负数)。
????????反码由原码符号位不变,其他位取反得到,就是当原码上的一位数字为0时,反码为1;原码为1时,反码为0。
????????补码由反码加1得到,这是二进制计算,不要当成十进制计算。因此可得到以下结果:(为了方便且直观数数,每4bit之间有空一格)
原码为:0000 0000 0000 0000 0000 0000 0000 0111
反码为:0000 0000 0000 0000 0000 0000 0000 0111
补码为:0000 0000 0000 0000 0000 0000 0000 0111
当对其进行左移运算的时候,是对补码进行移位的,因此需要反向计算才能得到结果。
?左移时:00000 0000 0000 0000 0000 0000 0000 1110
????????左边丢弃,右边补0,原码符号位不变。
因此,左移得到补码的结果为:
0000 0000 0000 0000 0000 0000 0000 1110
反码为:0000 0000 0000 0000 0000 0000 0000 1110
原码为:0000 0000 0000 0000 0000 0000 0000 1110
因此结果为14。
?由此可知,-7的原码,反码和补码分别如下:
原码为:1000 0000 0000 0000 0000 0000 0000 0111
反码为:1111 1111?1111 1111 1111 1111?1111 1000
补码为:1111 1111 1111?1111 1111 1111 1111 1001
左移时:11111 1111 1111?1111 1111 1111 1111 0010
左边丢弃,右边补0,原码符号位不变。
补码为:1111 1111?1111 1111 1111 1111?1111 0010
反码为:1111 1111?1111 1111 1111 1111?1111 0001
原码为:1000 0000 0000 0000 0000 0000 0000 1110
因此结果为-14。
右移操作符与左移操作符的原理类似,就是在右移的过程的时候,关于右边添加的数字当中有两种方法,一种是直接补零(也就是逻辑移位),一种是补原符号位(算术移位)。这些补位方法与编译器有关,不同的编译器的补位方法是不同的。本文使用的编译器为VS 2022,是算术移位的方法。右移操作符依旧以7和-7为例,方法与左移相似。
int c = 7;
int d = c >> 1;
printf("%d\n", c);
printf("%d\n", d);
当7向右移位时:
右移时:0000 0000 0000 0000 0000 0000 0000 00111
????????右边丢弃,(左边补0),原码符号位不变。
补码为:0000 0000 0000 0000 0000 0000 0000 0011
反码为:0000 0000 0000 0000 0000 0000 0000 0011
原码为:0000 0000 0000 0000 0000 0000 0000 0011
因此结果为3。
?当-7向右移位时:
右移时:1111 1111 1111?1111 1111 1111 1111?1100???1
右边丢弃,(左边补0),原码符号位不变。
补码为:1111 1111?1111 1111 1111 1111?1111 1100
反码为:1111 1111?1111 1111 1111 1111?1111 1011
原码为:1000 0000 0000 0000 0000 0000 0000 0100
因此结果为-4。