应该也是我们班的,比我学的好多了啊!!!
32位系统sizeof(int)=4,也就是有32位二进制数,内存中是以32位二进制补码的形式存放这个数的,int为有符号数,最前面一个数字是符号位,0表示正数,1表示负数。
也就是31位存储这个数的大小。
正数的补码就是他的原码本身,也就是num%2 ,余数倒叙排列,不够32位的前面补0,
例如,
00000000 00000000 00000000 00000001 表示1,
00000000 00000000 00000011 00000000 表示的是2的9次方+2的8次方=768。
最大int
01111111 11111111 11111111 11111111 表示2的31次方-1=2147483647
负数的补码是他对应正数的原码的反码,再+1得到的。
如-1,对应的1的原码
00000000 00000000 00000000 00000001
1的反码
11111111 11111111 11111111 11111110
反码加1为
11111111 11111111 11111111 11111111 这也就是内存中-1的存储方式。
int表示的最大正整数2147483647对应的负数-2147483647的二进制为
2147483647原码
01111111 11111111 11111111 11111111
反码
10000000 00000000 00000000 00000000
反码+1
10000000 00000000 00000000 00000001
那么int表示的最小的负数也就是
10000000 00000000 00000000 00000000 也就是 -2147483648
知道原理了如何打印一个数的32位二进制码呢?
1,先用原始的取余倒序排列,设要打印的数位num,
对于正数,num%2的值也就是第32位,(num/2)%2取余也就是第31位,((num/2)/2)%2也就是第30位……
定义一个有32个元素的数组a[32]来存放余数,用一个for循环来将余数赋给数组,
for (i=0;i<32;i++ )
{
a[i]=num%2;
num/=2;
}
a[0]存放第32位,a[1]存放第31位 , a[2]存放第30位…… 打印只要用下面语句倒序打印数组a,就可以了。a[31]a[30].......a[1]a[0]
for (j=31;j>=0;j--)
printf ( "%d",a[j] );
对于负数,他的存储方式也可以看做是,对应正数减去1之后的反码,如-1对应的正数1 减去1也就是0,
0的原码
00000000 00000000 00000000 00000000
反码
11111111 11111111 11111111 11111111 也就是-1的存储方式
if(num<0)
{
num = -num-1;
for (i=31;i>=0;i-- )
{
a[i]=num%2;
num/=2;
}
}这里我改变了一下赋值顺序,先将正整数第32位赋给a[31]……也就是a[0]存放第一位,打印的时候顺序打印数组就可以了(对于正数)。我们最终是要打印负数的二进制表示,所以还要取反,可以用下面的语句。
for (j=0;j<32;j++)
b[i] = (a[i]+1)%2;
那么,顺序打印数组b就可以了。
以下是这种方法的实验图:
2 用位操作打印。
用位的左移右移,我们可以将其他位都置0,
如 10100000 00001100 00000000 00000000我们左移2位再右移31位,就可以直接得到
00000000 00000000 00000000 00000001 也就是上面的第2个1移到了最后一位,可以得到第30位的值
每一位都如此操作,我们就可以得到每一位的值0或1,依次打印即可。
但是对于一个有符号的数,位的操作会使符号一起移动,但是如果符号位为1,你右移之后,符号位会自动补1,
如10000000 00001111 11110000 00001111 ,我们为了得到第1位的1,直接右移31位,我们预想的结果是
00000000 00000000 00000000 00000001 ,但实际上,由于符号位为1,每次右移符号位都会自动补1,右移1位
11000000 00000000 00000000 00000000,右移31位之后会变成
11111111 11111111 11111111 11111111。
为了得到想要的结果,我们可以把int赋值给一个unsigned int,这样,就可以用这个方法了。
可以看到,我用了3种位操作的方法来打印,第3种是我上面讲的,
第2种也是转换为无符号数,进行了一次位操作;
第1种是在不转换为无符号数的情况下,进行位操作打印。结果都是正确的。