我们在嵌入式的开发中难免会遇到 C 语言中的位运算符,因为我们需要效率,而位运算恰好效率比别的运算符效率高多了。位运算符直接对 bit 为进行操作,其效率最高。常见的位运算操作如下
我们在左移和右移时必须要注意:1、左操作数必须为整数类型,char 和 short 被隐式转换为 int 后进行移位操作;2、右操作数的范围必须为:[0,31];3、左移运算符 << 将运算数的二进制位左移,规则是高位丢弃低位补0;4、右移运算符 >> 把运算数的二进制位右移,规则是高位补符号位低位丢弃。
比如 0x1 << 2 + 3 的值会是多少呢?我们猜想有这么几种情况:1、先算 0x1 << 2 再把中间结果加 3,最终结果为 7;2、先算 2 + 3,所以结果为 32;3、这么混合的运算会出错。我们来看个示例代码,来看看编译器是如何处理的,代码如下:
#include <stdio.h> int main() { printf("%d\n", 3 << 2); printf("%d\n", 3 >> 1); printf("%d\n", -1 >> 1); printf("%d\n", 0x01 << 2 + 3); return 0; }
我们先来分析下这个代码,第5行 3 << 2 ==> 11 << 2 ==> 1100 ==> 12;第6行 3 >> 1 ==> 11 >> 1 ==> 1;编译后结果如下:
我们可以看到我们的分析是对的,第8行执行的是我们之前分析的第2种结果。
我们在 C 语言中应避免位运算符、逻辑运算符和数学运算符同时出现在一个表达式中;但位运算符、逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号()来表达计算次序;左移 n 为相当于乘以 2 的 n 次方(同理右移相当于除),但效率比数学运算符高。
我们下来看个实现宏函数交换的功能,这也是笔试中经常会遇到的一个题目,代码如下:
#define SWAP1(a, b) { int t = a; a = b; b = t; }
这是我们最常用的一种写法,但是它需要一个额外变量。我们下面来看个不需要借助额外变量的版本就可以完成的宏函数,代码如下:
#define SWAP2(a, b) { a = a + b; b = a - b; a = a - b; }
第4 行相当于 b = (a + b) - b ==> b = a;第5行相当于 a = (a + b) - b ==> a = (a + b) - a ==> a = b;这种也可以完成交换功能,但是它的效率似乎不是那么的高,因为要借助于数学运算。我们再来实现一个基于位运算实现的,代码如下:
#define SWAP3(a, b) { a = a ^ b; b = a ^ b; a = a ^ b; }
我们上面的代码效率是非常高的,我们来分析下,第 4 行相当于 b = (a ^ b) ^ b ==> b = a; 第5行相当于 a = (a ^ b) ^ b ==> a = (a ^ b) ^ a ==> a = b;这样也实现了交换的功能。
位运算与逻辑运算不同之处:1、位运算没有短路规则,每个操作数都参与运算;2、位运算的结果为整数,而不是 0 或 1;3、位运算的优先级高于逻辑运算优先级。
我们来看看下面这个示例代码:
#include <stdio.h> int main() { int i = 0; int j = 0; int k = 0; if( ++i | ++j & ++k ) { printf("Run here...\n"); } printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); return 0; }
我们分析下,第 9 行执行完,i、j、k分别就是1了。因为我们这块是位运算,所以没有短路规则。我们来看看编译结果:
是如我们分析的那样,如果我们第9行换成 if( ++i || ++j && ++k ) 这样,那么便是 i = 1,j = 0, k = 0 了,打印如下
通过我们今天学习的位运算符,总结如下:1、位运算符只能用于整数类型;2、左移和右移运算符的右操作数范围必须为[0, 31];3、位运算没有短路规则,所有操作数均会求值;4、位运算的效率高于四则运算和逻辑运算;5、运算优先级:四则运算 > 位运算 > 逻辑运算。后面我们会继续对 C 语言的学习。
欢迎大家一起来学习 C 语言,可以加我QQ:243343083。
原文地址:http://blog.51cto.com/12810168/2096718