蓝点工坊(http://www.bluedrum.cn) 创始人,App和嵌入式产品开发。同时也做相应培训和外包工作。 详细介绍 http://pan.baidu.com/s/1y2g88
全部博文(311)
分类: C/C++
2010-05-21 16:34:19
单目操作符.后面接一个整数类型.
格式: ~<数字变量| 数字常量>
给任何一个类型,按位取反.因此一个负数取反必须是一个正数.
简单判断一个数是否带符号位办法
#define IS_SIGNED(n) ( (((n)>=0) && (~(n)<0)) || (((n)<0) && (~(n)>0)) )
这个宏就是利用补码取反符号位也改变特性
简单判断一个类型是否带符号位的办法
#define ISUNSIGNED(type) (~((type)1)>0)
#define PRINT_INT(e) printf("%s=%d\n",#e, e)
PRINT_INT(7 | 3 );
PRINT_INT(7 | -1 );
|
|
在C语言里,数字的右边是低位,左边是高位。因此左移是从低位向高位移动。用<<表示。右移是从高位向低位移动,用>>表示。
C语言移位要分为无符号数,有符号数两大类移位。,比较简单的无符号数移位,移为逻辑移位。逻辑左移是高位移走和低位补零.而逻辑右移是低位移动,高位取零。
(1)unsigned char x=3;
x<<1是多少?x>>1是多少?
有符号数的移位称为算术移位。因为牵涉到符号位,基本原则是保持符号位不变。其中算术左移是符号位不变,次高数丢弃,低位补0.
但是算术右移的情况就比较复杂了。标准C语言并没有规定算术右移,次高位需要补什么值。因此不同编译器表示不同行为。其中gcc的的规定是 低位丢弃,次高位被符号位。
|
3写成二进制数是00000011;-3写成二进制数是(补码)11111101。
程序执行的时候,操作的是数值的编码表示,也就是数值在内存中的二进制表示。比如说,程序取-3的时候,就去取11111101。
(1)对无符号数3来说,x<<1往左移一位,最左边的位移掉了,最右边的移进来的位补零。变成00000110,所以结果是6;x>>1往右边移一位,由于是无符号数,所以逻辑右移,最右边一位移掉,最左边移进来的位补零,变成00000001,所以结果是1。
(2)对于有符号数3来说,x<<1往左移一位,最左边的位移掉了,最右边的移进来的位补零。变成00000110,所以结果是6;x>>1往右边移一位,由于是有符号数,可能发生逻辑右移,也可能发生算术右移,这一点,C标准并没有明确地指定是使用逻辑右移还是算术右移。但大多数的机器都使用算术右移,变成00000001,所以结果还是1。但是请注意,这只是说大多数的机器是这样的,你敢保证自己不会碰到特殊情况吗?
(3)对于有符号数-3来说,x<<1往左移一位,最左边的位移掉了,最右边的移进来的位补零。变成11111010,结果是-6。往右移一位,由于是有符号数,可能发生逻辑右移,也可能发生算术右移。大多数机器使用算术右移,变成11111110,结果是-2。
3.逻辑位操作应用
注意一般C语言的第几位,是以0为起始的.下列均是如此
3.1 清位操作
清位操作是指把某几位置为0,其余位不变.
清位操作要利用0与任意位相与均为0来完成,其余位不变则要利用1与任何相与值不变的特性.为了形成这样数,要把一个置0位为1数取反即可,即用 &=~操作.
假设置 12-13 bit的为0 ,则二进制展开为 11000000000000,换算为 0x3000
rADCDAT0 &=~0x3000;
清位采用左移,或右移来置位,以置 14bit为例 ,这样将大大增强代码可读性.
rADCDAT0 &=~(0x1<<14);
3.2 置位操作
置位操作指把某几位置为1,其余位不变.
置位操作是利用1与任意位来位或的特性来实现的
参见如下代码
rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
这里的 0<<6会改变最终的值吗?写在这里是起什么作用?
3.3 取位操作
取位操作是判断一个数的一些值,并且不能改变这个数.
需要再额外加上一个判断表示式。才能得到结果
(rADCDAT0 & 0x3000)==0x3000
练习题
1.在汇编语言还有一种叫作循环左/右移的操作,以循环左移为例,每一次移走的最高位移到最右的低上。循环右移刚好相反,请用C语言写一个无符号整数的循环左移和右移函数
2.请写三个宏,来分别实现清位,置位和取位操作
CLR_BIT(val,num)
SET_BIT(val,num)
TEST_BIT(val,num)