C 位操作 详解

一、位运算:

|  按位或操作符:result=exp1|exp2;当exp1和exp2中对应位中至少有一个为1时,result中对应位为1,否则为0。

& 按位与操作符::result=exp1&exp2;当exp1和exp2中对应位全为1时,result中对应位为1,否则为0。

^  按位异或或操作符:result=exp1^exp2;当exp1和exp2中对应位不相同时,result中对应位为1,否则为0。

~  按位取反(反转)操作符:将位容器中的所有位都反转,1变为0,0变为1。

|=,&=,^= 分别对应|&^三种操作符的复合操作符。

 

应用:(不用中间变量交换两个值)

void  myswap( int &a, int &b)

{

         a = a ^ b;

         b = a ^ b;

         a = a ^ b;

}

原因:a^b^b 之后,a的值不变。

另解:

 a = a + b;

 b = a - b;

 a = a - b;

但此种方法可能有溢出,没有第一种方法好。

 

 

二、定点数的移位运算

1、什么样的数据类型可以直接移位

char、short、int、long、unsigned char、unsigned short、unsigned int、unsigned long都可以进行移位操作,而double、float、bool、long double则不可以进行移位操作。

2、有符号数据类型的移位操作

对于char、short、int、long这些有符号的数据类型:

  • 对负数进行左移:符号位始终为1,其他位左移 ,后面添0
  • 对正数进行左移:所有位左移,即 <<,可能会变成负数
  • 对负数进行右移:左边添1 ,右边丢弃。
  • 对正数进行右移:所有位右移,即 >>

3、无符号数据类型的移位操作

对于unsigned char、unsigned short、unsigned int、unsigned long这些无符号数据类型,没有特殊要说明的,使用<< 和 >> 操作符就OK了

 

移位详细原理:

定点数的移位运算也称为移位操作。左移或右移n位相当于乘以或除以2的n次方。当计算机没有乘(除)运算线路时,可以采用移位和加法相结合,实现乘(除)运算。机器数字长往往是固定的,当机器数左移或右移时,必然会使其低位或高位出现空位。对空出的空位应该添补0还是1与机器数采用有符号数还是无符号数有关。有符号数的移位称为算术移位,无符号数的移位称为逻辑移位。

(1)      算术移位:

不同码制机器数算术移位后的空位添补规则

码   制

添补代码

正数

原码、补码、反码

0

 

原码

0

负数

补码

左移添0

右移添1

反   码

1

  由上表可得出如下结论:

  (1)机器数为正时,不论左移或右移,添补代码均为0。

  (2)由于负数的原码其数值部分与真值相同,故在移位时只要使符号位不变,其空位均添0。

  (3)由于负数的反码其各位除符号位外与负数的原码正好相反,故移位后所添的代码应与原码相反,不论左移或右移,即全部添1。

  (4)分析任意负数的补码可发现,当对其由低位向高位找到第一个“1”时,在此“1”左边的各位均与对应的反码相同,而在此“1”右边的各位(包括此“1”在内)均与对应的原码相同,即添0;右移时空位出现在高位,则添补的代码应与反码相同,即添1。

 

(2)逻辑移位:逻辑移位的规则是逻辑左移时,高位移出,低位添0;逻辑右移时,低位移出,高位添0。

 

 

 

以下是一种简明的说法:

对于无符号数的移位(逻辑移位)很简单,直接变成2进制,经过移位后, 一端的位被"挤掉",而另一端空出的位以0 填补。

而对于有符号数移位(算术移位)则相对复杂一点,如果符号位为0(即正数),其移位效果与无符号数 移位一致。

容易出错的是负数移位。负数移位需先将负数变成计算机的补码形式,即保留符号位而其它位取反加1。如 int16型的-15,正常翻译为1000 0000 0000 1111,保留符号位其它位取反加1,变成1111 1111 1111 0001(0xFFF1)。变成这种形式后就可以对其进行移位了,左移,保留符号位,左边被挤掉的不管,右边填0;而右移的时候略有不同,保留符号位,右边被挤掉的部分丢弃,而高位填符号位1。如-15,右移3位,则变成FFFE(-2)。显然有符号数移位并不等效于乘法或除法。

如果将有符号数强制类型转换为无符号,则将其2进制补码形式翻译为无符号数即可。如

short aa = -15;

unsigned short bb;

bb = (unsigned short) aa;

则bb变成0xFFF1(65521),实际上就是-15的计算机表示。

 

 

例:设机器数字长为8位(含一位符号位),若A=±26,写出三种机器数左、右移一位和两位后的表示形式及对应的真值,并分析结果的正确性。

  解:(1)A=+26=(+11010)2

  则[A]原=[A]补 =[A]反=0,0011010

  移位结果表示如下:

移位操作

机  器   数

对应的真值

[A]原=[A]补=[A]反

移位前

0,0011010

+26

左移一位

0,0110100

+52

左移两位

0,1101000

+104

右移一位

0,0001101

+13

右移两位

0,0000110

+6

  可见,对于正数,三种机器数移位后符号位不变,左移时最高数位丢1,结果出错;右移时最低数位丢1,影响精度。

  (2)A=-26=(-11010)2

  三种机器数移位结果示于下表。

移位操作

机  器   数

对应的真值

移位前

1,0011010

-26

左移一位

1,0110100

-52

左移两位

1,1101000

-104

右移一位

1,0001101

-13

右移两位

1,0000110

-6

移位前

1,1100110

-26

左移一位

1,1001100

-52

左移两位

1,0011000

-104

右移一位

1,1110011

-13

右移两位

1,1111001

-7

移位前

1,1100101

-26

左移一位

1,1001011

-52

左移两位

1,0010111

-104

右移一位

1,1110010

-13

右移两位

1,1111001

-6

  可见,对于负数,三种机器数移位后符号位均不变。负数的原码左移时,高位丢1,结果出错;低位丢1,影响精度。负数的补码左移时,高位丢0,结果出错;低位丢1,影响精度。负数的反码左移时,高位丢0,结果出错;低位丢0,影响精度。

应用:(不用比较运算符来比较大小)

int mymin(int a, int b )

{

     int mask = (a - b)>>31;

     return (a & mask) | (b & ~mask);

}

 

int mymax(int a, int b )

{

     int mask = (a - b)>>31;

     return (a & ~mask) | (b & mask);

}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值