C/C++位操作方法及应用

引入

  我们经常在数据处理中会遇到这样的情况:需要取出特定位,或者将数据进行拆分分别获取。这时处理数据的方法通常有两种,一种是乘除法,另一种是移位运算。

比较

  例如我们需要对一个16位的数据进行拆分传输,分为高8位和低8位依次传输。首先我们会很容易想到用乘除法运算来解决:
x1 = x / 256;
x2 = x % 256;
而移位运算则是
x1 = x >> 8;
x2 = x & 0x00FF;
  首先从效率上看,移位操作只占用两个机器周期,而乘除法占用四个机器周期。并且移位操作对于硬件来说更容易实现的。

应用

常见位操作包括|、&、^、<<、>>
  比如我们需要将一串数据取出,那么就需要移位直到那串数据的最低位。如果需要对特定位进行置零和取反,则利用利用&和^来实现。如:
对0x146的第9-16位进行置零或取反
a = 0x146 & 0xF0F;
a = 0x146 ^ 0x0F0

一个注意事项

  我们知道一个无符号数左右移时,一边移除数据,另一边补零,但是这都有一个前提:你得知道计算机在读取你的数据时一次操作几位。举个例子,如果你在51单片机上进行移位操作,你定义了一个8位的unsigned char型数据0xFF,如果你左移了4位,就相当于移除了高4位的数据,打印出来后就是0xF0,这是丝毫没有问题的,但是你如果在vscode或者vs上进行这样的实验:

unsigned char a = 240;
printf("%x\r\n", a<<8);
printf("%x\r\n", a<<28);

编译输出结果如下:

PS C:\Users\Raymond_Meng\Desktop\test> gcc test.c -o tesr
PS C:\Users\Raymond_Meng\Desktop\test> .\tesr.exe        
f000
0

  你会发现8位的数据并没有在移动8位后移除,而是又向左移动了8位。而且左移了28位发现结果变成了0。进一步实验:
printf("%x\r\n", a<<32);
此时终端出现warning:

test.c: In function 'main':
test.c:10:36: warning: left shift count >= width of type [-Wshift-count-overflow]

移位寄存器溢出
  这是跟编译器的位数有关系的。我的IDE采用的是如下的编译器:
gcc.exe (MinGW.org GCC-8.2.0-3) 8.2.0
  gcc是32位MinGW下的的编译器,所以很容易想到上述问题是和编译器的操作位数相关的。我们知道我们定义了一个数据类型的数据变量,编译器会给它分配一块内存空间和地址,并且内存是连续存储的。编译器在读取对应地址的数据时,一次读取32位,这是由内存物理空间决定的。所以,虽然我们定义了一个8位的数据变量,但是移位寄存器最大可以移到32位但此时就会有溢出,而这并不代表char类型可以存储32位的数据,只是编译器的原因导致移位后数据并没有被丢弃。
而在一些低运算位的处理器或者微控制单元中,就很容易通过移位来进行一次运算。对于一个16位数据7896(0x1ED8),我们需要分别取低八位和高八位,就可以直接这样实现:

d = (7896 << 8) >> 8;
g = 7896 >> 8; 

END

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值