深入总结嵌入式位操作运算符
位运算应用法则
清零取位要用与,某位置1要用或,取反和交换用异或
移位运算要诀
1.他们都是双目运算符,两个运算分量都是整形,结果也是整形。
2.“<<”左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2;
3“>>”右移:右边的位被挤掉了,对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或1,这取决于不同的计算系统。
4“>>>”运算符:右边的位被挤掉,对于左边移出的空位一概补上0;
位运算的应用(源操作数a 掩码b)
(1)按位与&
1.清除某特定位(b中特定位置0,其余位为1,a=a&b)
2.取某数中指定位(b中特定位置1,其余位为0,a=a&b)
(2)按位或--|
常用来将源操作数某些位置1,其它位置不变。(b中特定位置1,其余位为0,a=a|b)
(3)位异或--^
相同为0,不同为1
1 使特定位的值取反
例如对数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算。
10100001^00000110 = 10100111
2 不引入第三变量,交换两个变量的值
例如交换两个整数a=10100001,b=00000110的值,可通过下列语句实现:
a = a^b; //a=10100111
b = b^a; //b=10100001
a = a^b; //a=00000110
3.快速判断两个值是否相等
举例1: 判断两个整数a,b是否相等,则可通过下列语句实现:
return ((a ^ b) == 0)
举例2: Linux中最初的ipv6_addr_equal()函数的实现如下:
static inline int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
{
return (a1->s6_addr32[0] == a2->s6_addr32[0] &&
a1->s6_addr32[1] == a2->s6_addr32[1] &&
a1->s6_addr32[2] == a2->s6_addr32[2] &&
a1->s6_addr32[3] == a2->s6_addr32[3]);
}
可以利用按位异或实现快速比较, 最新的实现已经修改为:
static inline int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
{
return (((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
(a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
(a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
(a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0);
}
4.基于按位异或的加密解密算法
class E
{ public static void main(String args[ ])
{
char a1='十' , a2='点' , a3='进' , a4='攻' ;
char secret='8' ;
a1=(char) (a1^secret);
a2=(char) (a2^secret);
a3=(char) (a3^secret);
a4=(char) (a4^secret);
System.out.println("密文:"+a1+a2+a3+a4);
a1=(char) (a1^secret);
a2=(char) (a2^secret);
a3=(char) (a3^secret);
a4=(char) (a4^secret);
System.out.println("原文:"+a1+a2+a3+a4);
}
}
如果两个数相应的位上一样,结果就是0,不一样就是1
所以111^101=010
那加密的过程就是逐个字符跟那个secret字符异或运算.
解密的过程就是密文再跟同一个字符异或运算
010^101=111
二进制补码运算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-
-(~x) = x+
~(-x) = x-
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)^((x^y)&((x-y)^x))
x<=y: (x|~y)&((x^y)|~(y-x))
x< y: (~x&y)|((~x|y)&(x-y))//无符号x,y比较
x<=y: (~x|y)&((x^y)|~(y-x))//无符号x,y比较
应用举例
(1) 判断int型变量a是奇数还是偶数
a&1 = 0 偶数
a&1 = 1 奇数
(2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&
(3) 将int型变量a的第k位清0,即a=a&~(1< (4) 将int型变量a的第k位置1, 即a=a|(1< (5) int型变量循环左移k次,即a=a<>16-k (设sizeof(int)=16)
(6) int型变量a循环右移k次,即a=a>>k|a<<16-k (设sizeof(int)=16)
(7)整数的平均值
对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
(8)判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂
boolean power2(int x)
{
return ((x&(x-1))==0)&&(x!=0);
}
(9)计算绝对值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ; //or: (x+y)^y
}
(10)取模运算转化成位运算 (在不产生溢出的情况下):a % (2^n) 等价于 a & (2^n - 1)
(11)乘法运算转化成位运算 (在不产生溢出的情况下):a * (2^n) 等价于 a<< n
右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2;
(12)除法运算转化成位运算 (在不产生溢出的情况下):a / (2^n) 等价于 a>> n
右边的位被挤掉。对于左边移出的空位,补零,其值相当于除2;
例: 12/8 == 12>>3
(13) a % 2 等价于 a & 1
(14) if (x == a) x= b;
else x= a;
等价于 x= a ^ b ^ x;
(15) x 的 相反数表示为 (~x+1)
(16) 实现最低n位为1,其余位为0的位串信息:~(~0 << n)
(17)截取变量x自p位开始的右边n位的信息:(x >> (1+p-n)) & ~(~0 << n)
(1)截取old变量第row位,并将该位信息装配到变量new的第15-k位:new |= ((old >> row) & 1) << (15 – k)
(19)设s不等于全0,代码寻找最右边为1的位的序号j:
for(j = 0; ((1 << j) & s) == 0; j++) ;
return j;//由于1每次左移过程中只要遇到1此时相与为1,返回此时的位置J
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)