最近小小的做了点计算机内部的位计算。用的是32位的xp系统,xp系统内部的编码字节顺序是小端法(另有些系统是采用大端法),即机器选择在存储器中按照从最低有效字节到最高有效字节的顺序存储对象。
以int类型为例,32位的xp系统的int是用4byte来表示的,也就是32个bit。所谓无符号的int数即为32个bit全部用来表示数,这样无符号的int的数范围就为0~4 294 967 295 。有符号的int数即为有31个bit是用来表示数的值,然后最后一个bit是用来表示该数的正负的,0表示正数,1表示负数,这样无符号的int的数的范围就为-2 147 483 648~2 147 483 647。
举个例子比如一个16进制值为0x01234567的数,假设在机器上的地址为0x100到0x103,小端法排列的方式是 0x100 :67 , 0x101 : 45 , 0x102 : 23 , 0x103 : 01
而大端法排列为0x100 :01 , 0x101 : 23 , 0x102 : 45 , 0x103 : 67
由于计算机系统的内部是运用二进制的补码来表示数据的,此处以32位系统为例,以下也应用c语言作为样本语言对编码进行描述。
首先我将介绍下怎么样用c语言将数以字节方式打印出来。以下是《深入理解计算机系统》中介绍的一段代码
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int len)
{
int i;
for(i=0;i<len;i++)
printf("%.2x" , start[i]);
printf("/n");
}
用该代码段打印出来的数将以十六进制方式呈现出来,例如:1 将输出为01000000 ,-1输出为ffffffff。从这个例子中可以看到,01排在输出的最左边,这说明xp的系统确实是用小端法排列字节顺序的,而ffffffff佐证了系统内部确实是用的二进制的补码来表示数的。
写完了系统内部的数编码方式,现在开始具体说下怎么样用c语言进行位计算。c语言支持的位操作符有~,|,&,!,^,+,<<,>>。
~用来求二进制码的反码。(例如:~1000 0000=0111 1111)
| 用来对二进制码进行OR操作(例如:1010|0110=1110)
& 用来对二进制码进行AND操作(例如:1100&1001=1000)
!用来对二进制码进行求布尔操作,及对非零的数操作全返回0,对零操作返回1(例如:!1=0 , !0=1)
^ 用来对二进制码进行与或操作(例如:2^3=1)
<<用来实现对二进制码内的某个字符进行左移操作。x<<k表示将x的二进制码向左移动k位,左边的k个位上的值将被丢失,而右边将会通过补0的方式来补位,例如(5<<2=4,即101<<2=100)这里要注意<<的优先级低于加号和减号。
>>的用法是右移操作,其他参照左移符。需要注意的是右移有两个形式:第一种形式是逻辑的,逻辑右移在左端补0(例如:1111>>2=0011);另一种形式是算术右移,它将在左端填充原来最左端的值(例如:1010>>2=1110)。
介绍了c语言的位操作符之后,在来说说这些二进制符在计算的时候所遵循的规则。
交换性:a|b=b|a , a&b=b&a
结合性:(a|b)|c=a|(b|c),(a&b)&c=a&(b&c)
分配性:a&(b|c)=(a&b)|(a&c) ,a|(b&c)=(a|b)&(a|c)
同一性:a|0=a,a&1=a
消除性:a&0=0
相消性:~(~a)=a
相补性:a|~a=1,a&~a=0
幂等性:a&a=a,a|a=a
吸收性:a|(a&b)=a,a&(a|b)=a
DeMorgan性:~(a&b)=~a|~b , ~(a|b)=~a&~b
现在简单介绍下几种位操作的应用。
(1)判断一个数是否为零: int isZero(int x){ return !(x^0);}
(2)获得-1:return ~0;
(3)获得最大的有符号int整数:~(1<<31);
(4)从一个数中提取某一位上的数,例如getByte(0x12345678,1)=0x56 int getByte(int x,int n){ return (x>>(n<<3))&0xff ;}
(5)返回一个数的相反数 (~x)+1
(6)确定一个数是否为正整数(不包括0):!(x&(1<<31))&!(!x)
关于二进制编码的问题暂时就写到这里,如有什么错误请与我联系(ultimate_z@126.com),我将在弄清楚后进行处理,谢谢!!!!!!!!