C语言_用宏定义实现位运算

这两天学习了C的位运算,记录一下,这个知识也是看Linux内核的基础。

与或非

位与& 和 逻辑与&&

  • 位与的真值表的特点是:只有1&1结果才1;1&0,0&1,0&0结果都为0.
  • 位与操作与逻辑与操作一起记住,把非0的数看成是1,0做为0,然后再进行与&运算,例如0xffff&&0x11=1;

位或| 和 逻辑或||

  • 位或只有两个0位或结果为0,其余都是1,真值表:1|1=1,1|0=1,0|1=1,0|0=0
  • 两个操作数作为整体操作,把非0的数看成是1,0看成是0,进行位与操作。

位取反~和逻辑取反!

  • 位取反|每个二进制位按位取反,0变1,1变0。
  • 逻辑取反,非0的数当做真,0作为假,逻辑运算:真变假,假变帧。
    下面是例子,ARM中的移位操作都是无符号数;ARM中的读改写都是一体的,想要对一个寄存器中的某些特定位进行读改写,要将这个寄存器中所有的值读出来,然后修改特定位,最后再将修改好的值,写入寄存器。

与或非使用场景

特定位清零用&

如果希望将一个寄存器的某些特定位变为0,而不影响其他位,可以构造一个合适的由1和0组成的数和这个寄存器原来的值进行与操作&,可将特定位清零。
例如:将0xAAAAAAAA bit8-bit15清0,其他位不变,可以将这个数与oxFFFF00FF进行位与操作,得到0xAAAA00AA

特定位置1用|

或|运算的特定,与1则为1,遇到0为0.

特定位取反用异或操作

异或运算特点:相等为0,不等为1.记忆方法是:不同时进行或运算。

左移<<和右移>>

左移:移动后,后面的空缺自动补零。
右移:分为逻辑右移和算术右移

  • 逻辑右移:不管什么类型,移动后,左边补零‘
  • 算术右移,如果是无符号数,则左边补零;如果是负数,左边补1;

如何构造特定的数

使用位移<<和>>

想要操作寄存器中的某些特定位,要构造一个数,与寄存器中的数进行运算,怎样才能构造这样的数?可以使用右移来构造,例如需要一个bit3-bit7为0的数,则可以11111<<3,写成0x1f<<3.就可以得到。
在这里插入图片描述
更难一点的:bit3-bit7为1,同时bit23-bit25为1,其余位为0.
解法:(0x1f<<3)|(7<<23);

使用位取反~ 获得特定位为0的二进制数

例如:获取bit4-bit10为0的数,其他位为1的数,如何做?
在这里插入图片描述

  • 解法1:利用上面的方法,就是把这个数的其他位都置1,这样操作:(0xf<<0)|(0xffff1<<11),找个数左移11位,就可以得到。
    这种方法缺点是,1太多了。
  • 解法2:构造一个这个数的相反数,再与原来的数进行&操作。~(0x7f<<4).

总结

  • 如果想要的这个数,1的位数比较少,大部分为0, 则可以通过连续很多个1左移得到。
  • 如果想要的数,0的位数表较多,大部分位1,可先构建取反数,然后再取反。
  • 总之:要置1用|,要置0用&,取反用~,再配合左移和右移获得。

位运算练习

练习1 :给定一个整型数a,设置a的bit4,保证其他位不变。

a|(1<<3)
在这里插入图片描述
输出结果16.

练习2:给定一个整形数a,设置a的bit3~bit7,保持其他位不变。

a = a | (ob11111<<3)
a|= (0x1f << 3)

练习3:给定一个整型数a,清除a的bit15,保证其他位不变。

第一步: 1 << 15
在这里插入图片描述

第二步: ~(1 << 15)
在这里插入图片描述

第三步: a = a & (~(0x1ff))
最后a变为0
在这里插入图片描述

练习4:给定一个整形数a,清除a的bit15~bit23,保持其他位不变。

第一步:0x1ff<<15
第二步:~(0x1ff) << 15
第三步:a = a & ~(0x1ff) << 15

练习5:给定一个整形数a,取出a的bit3~bit8。

第一步:先将bit3-bit8不变,其余位全部清零。
a & (0x3f << 3)
第二步:再将这个数,右移3位。
a = a >> 3;

练习6:用C给一个寄存器的bit7~bit17赋值937(其余位不受影响)。

第一步:先将bit7-bit17清0
a = a & ~(0x7ff << 7);
第二步:再将937写入即可。
a = a | (937<<7)

练习7:用C语言将一个寄存器的bit7~bit17中的值加17(其余位不受影响)。

第一步:先读出bit7-bit17的值:将bit7-bit17不变,其余位都是0.
b = a ;
b = b & ~(0x7ff << 7)
b =b >> 7;
第二步: 再给这个值加上17,
b += 17;
第三步:将bit7-bit17清零
a = a & ~(0x7ff << 7)
第四步:
a |= (a <<b)
在这里插入图片描述

用宏完成上述操作(有空再整理)

用宏时,最起码的在#define后边加上括号,要不然就是最不专业的C程序员。

第一题,用宏定义将32位数x的第n位置位。

分析:置位的意思是,赋值为1.第n位对应的是bit(n-1)位。
第一步:(x | (1 << (n-1))) // 最外边加一层括号。
第二步:#define SET_BIT_N(x,n) (x | (1 << (n-1)))
专业的写法:(x | ((1U) << (n-1))) ,这种方式充分考虑了,1作为一个无符号整数

第二题,用宏定义将32位数x的第n位清零

第一步:x & ~(1U << (n-1))
第二步:#define CLEAR_BIT_N(x,n) (x & ~(1U) << (n-1))
还有更复杂的宏定义,留着看内核的时候,再过来看。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值