【编程基础】如何了解c语言中的位运算?

计算机的各种运算最小单位是字节,但是有时候只对某个位(bit)感兴趣,C语言提供了一些列位运算符来完成这个任务。这些操作非常重要,尤其是在嵌入式开发中会常常用到,这也是为什么嵌入式基本上都是选用C语言来开发的重要原因之一。

C语言的位运算有一下六中: & 按位与 | 按位或 ^ 按位亦或 ~ 按位取反 << 左移 >> 右移

按位与& 两个对应的位为1,运算后对应位为1,否则为0,比如:10101100 & 01101001 = 00101000。

按位或| 两个对应位中只要有一个为1,运算后对应位就为1,否则为0,比如:10101100 | 01101001 = 11101101。

按位亦或^ 两个对应位中如果不同,运算后对应位就为1,否则相同就为0,比如:10101100 ^ 01101001 = 11000101。

按位取反~ 将原来对应位取反,1变0,0变1。这个是一个单目运算,也就是只需要一个操作数,比如:~10101100 = 01010011。

左移<< 将整个位左移指定位数,比如:10101100 << 3,结果为01100 000。前面的三位101被移走,后面补充3个0。

右移>> 将整个位右移指定位数,比如:10101100 >> 3,结果为多少?右移有点不一样,它分逻辑右移和算术右移。如果是逻辑右移,向右移动后,左边补0;如果是算术右移,则左边最高位是0时,就补0,如果左边最高位是1,则根据编译器不同可能会不同。比如:逻辑右移:10101100 >> 3,结果为000 10101。右边的100被移走,左边补0;算术右移:10101100 >> 3,结果可能为111 10101,也可能为000 10101。当然右边的100还是被移走。

以上基本的位运算其实很简单,很多人一看就理解了,但是要灵活应用却不是那么简单的。比如有群友提出清除位是怎么回事,其实就是这个为位运算了,将一个数的某一个位设置为0。比如我们要将10101100这个二进制位的左边第三位清除,则可以用如下办法:10101100 & 11011111。

一般实际编程中都用一个mask来清除和设置。像上面这个问题,我们定义一个mask为0x20的数(00100000),要设置左边第三位,者只需要10101100 | mask;要清除时,用10101100 & ~mask即可。这样所有位我们都可以定义mask来操作。这个在嵌入式上用的非常广泛,比如设置和清除寄存器。类似的应用还有很多,下面举一个例子:

位映射:

unsigned char data[32]; #define BIT_SET(a, n) (((a)[(n) >> 3]) |= (1 << ((n) & 0x07))) #define BIT_GET(a, n) ((((a)[(n) >> 3]) >> ((n) & 0x07)) & 0x01) #define BIT_CLR(a, n) (((a)[(n) >> 3]) &= (~(1 << ((n) & 0x07))))

它可以用一个位来记录某个对应的操作。

求绝对值:

int myabs(int n) { int f = n >> 31; n ^= f; n -= f; return n; }

计算一个整数中有多少位是1:

int count(unsigned int v) { v -= (v>>1) & 0x55555555; v = (v & 0x33333333) + ((v>>2) & 0x33333333); v = (v + (v>>4)) & 0x0F0F0F0F; v += v>>8; v += v>>16; return v & 0x3F; }

颠倒一个字节的位序:

unsigned char reverse(unsigned char b) { b = (b << 4) + (b >> 4); b = ((b & 0x33) << 2) + ((b & 0xCC) >> 2); b = ((b & 0x55) << 1) + ((b & 0xAA) >> 1); return b; }

奇偶校验计算:

static int Parity(int val) { int parity = val; parity ^= parity >> 16; parity ^= parity >> 8; parity ^= parity >> 4; parity ^= parity >> 2; parity ^= parity >> 1; return parity & 0x00000001; }

还有更复杂的汉明码解码等就不在这里举例了,位运算本身是很简单的,但是真正应用起来是非常复杂的。但是他的效率也很高,同样一个任务,往往用位运算能提高速度。

原文发布于微信公众号 - 程序员互动联盟(coder_online)

原文发表时间:2015-10-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Petrichor的专栏

python: TODO 助记符

TODO 在 python 中作为一种 助记符 (Mnemonics),用来解释 将要做什么 。

17220
来自专栏技术沉淀

Python: json模块实例详解

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。

27040
来自专栏JavaEdge

深入理解JDK动态代理机制

34060
来自专栏CreateAMind

coach运行流程梳理

12020
来自专栏我爱编程

Day12面向对象高级编程3/3

使用元类 type() class Hello(object): def hello(self,name='World!'): prin...

36570
来自专栏nnngu

java中堆和栈的区别

堆和栈都是Java用来在RAM中存放数据的地方。 堆 (1)Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器...

24650
来自专栏专注 Java 基础分享

虚拟机字节码执行引擎

所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给出的字节码指令,基于栈解释器的一种执行机制。通俗点来说,也就是 JVM 解析字节码指令...

26940
来自专栏闻道于事

Java之StringBuffer,StringBuilder,Math,Date,SimpleDateFormat,UUID,File

java.lang  类 StringBuffer java.lang.Object java.lang.StringBuffer 所有已实现的接口:...

40060
来自专栏积累沉淀

线程的分类

1.主线程 main方法。 2.精灵线程 特点: (1)设置为精灵线程的方法:setDaemon(true); (2)其他线程结束了 精灵线程也...

21080
来自专栏yang0range

Java的面试基础题(二)

1)特点:存储对象;长度可变;存储对象的类型可不同 2)Collection (1)List:有序的;元素可重复,有索引 (add(index, elem...

19920

扫码关注云+社区

领取腾讯云代金券