第12课 - 位运算符分析
- 位运算符
& | 按位与 | ~ | 取反 |
| | 按位或 | << | 左移 |
^ | 按位异或 | >> | 右移 |
C语言是嵌入式开发的首选,我们在进行嵌入式开发的,串口和并口的使用的时候。我们还是要使用位运算的,这样可以更加方便的操作。
结合律:a&b&c = (a&b)&c = a&(b&c)
交换律:a&b = b&a
- 左移和右移的注意事项
左移:
左移运算符<<将运算数的二进制位左移,规则是:高位丢弃,地位补0。
右移:
右移运算符>>把运算数的二进制位右移,规则是:高位补符号位,地位丢弃。
l 0x1<<2+3的值会是什么?
先算2+3,所以结果为32。加减法的优先级高于位运算符。但是,这种东西,经常慧然人混淆,所以我们引出放错准则。
- 防错准则
避免位运算符,裸机运算符和数学运算符同时出现在一个表达式中。
当位运算符,逻辑运算符和数学运算符需要同时参与运算的时候,尽量使用括号()来表达计算。
小技巧:
左移n位相当于乘以2的n次方,但效率比数学运算符高
右移n位相当于除以2的n次方,但效率比数学运算符高
- 交换两个变量分析
#include <stdio.h>
#define SWAP1(a,b) \
{ \
int temp = a; \
a = b; \
b = temp; \
}
\\用了第三个变量
#define SWAP2(a,b) \
{ \
a = a + b; \
b = a - b; \
a = a - b; \
}
\\ 仅仅用了两个变量
#define SWAP3(a,b) \
{ \
a = a ^ b; \
b = a ^ b; \
a = a ^ b; \
}
/*(1)a = a ^ b;
(2)b = a ^ b = a ^ b ^ b = a ^ (b ^ b) = a ^ 0 = a;
(3)a = a ^ b = a ^ b ^ a = (a ^ a) ^ b = 0 ^ b = b;
用到了结合律的使用,不会有溢出的可能*/
int main()
{
int a = 1;
int b = 2;
SWAP1(a,b);
SWAP2(a,b);
SWAP3(a,b);
return 0;
}
第三种方法很好,因为位运算符是比加减法的运算效率还要高的。
- 面试题详解:
有一个数列,其中的自然数都是以偶数的形式出现,只有一个自然数出现的次数为
奇数次。编写程序找出这个自然数。
自己编写的函数(找奇数,弄错了):
#include<stdio.h>
int main()
{
int a[10] = {2,4,6,3,0,12,88,8,10,14};
int i;
int k;
int m;
for(i=0;i<10;i++)
{
k = a[i] % 2;
if(k == 1)
m = a[i];
}
printf("%d\n",m);
return 0;
}
运算结果:3
教程中的例子:
#include<stdio.h>
#define DIM(a) (sizeof(a)/sizeof(*a))
int main()
{
int a[] = {2, 3, 5, 7, 2, 2, 2, 3, 5, 7, 1, 1, 1};
int find =0;
int i;
for(i=0;i<DIM(a);i++)
{
find = find ^ a[i];
}
printf("find = %d\n",find);
return 0;
}
运行结果:find = 1
- 思考
l &&, ||, !与&, |, ~的意义是否相同?它们可以在条件表达式中交替使用吗?为什么 ?
不可以,一个是针对数字,一个是语句中的变量。
l 1<<32的结果是什么?1<<-1的结果又是什么?为什么 ?
1默认为unsigned int,1左移33位,1已经移出左侧最高位,得到的是0。
1L是unsigned long int,1左移33位得到的数据是0x0000000400000000。
1<<-1的结果是0。