前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言位操作(二)

C语言位操作(二)

作者头像
用户6280468
发布2022-03-21 09:36:45
1.1K0
发布2022-03-21 09:36:45
举报
文章被收录于专栏:txp玩Linux

今天给大家继续分享C语言里面的位操作;这个礼拜熟悉了一下公司代码,第一次看内核代码的感受就是(看的是 rtos——threadx 和 Linux),C 语言基础要好,不然看源代码很是难受,而且一般企业里面的项目都是非常庞大的,所有的一切都要靠自己去理解,所以的话平时一些c语言基础要掌握好,比如说:指针,二级指针,函数指针,指针函数,结构体数组指针,结构体指针数组,数组指针,指针数组,结构体等,甚至一些 GNU 里面的c 语言用法,可能在平时的单片机代码里面不是很常见,比如说:  attribute 的多种用法,week 弱定义,volatile 的使用,内联函数的使用,结构体位域的使用等等,当然也会有C++代码;现在越来越觉得C++和C这种语言是真的好,很强大分享,很香。想必刚才说的里面有些读者可能没用甚至也没有听过(当然您是老手的话,那可是小菜一碟啊!),没关系,作者也是一边学习一边总结的,后面也会总结分享出来的,希望对各位有用。

一、得明白位操作的用武之地:

        其实大家写过单片机的程序都或多或少的接触到这个位擦做,就像当初作者学习 stm32 的时候,点亮一个 led 灯,用寄存器的方法去实现,这个至今都记忆犹新,哈哈;所以说,做底层开发的话,一定要会位操作,也就是对一些外设寄存器的位操作,这是嵌入式工程师必备的一个小技能。

二、位操作的几种特殊实现方式:

1、特定位清零用"&"

我们在对外设寄存操作的话,就经常要这样干,以至于来实现自己想要的功能来。比如说如果希望将一个寄存器的某些特定位变成 0 而不影响其他位,可以构造一个合适的 1 和 0 组成的数和这个寄存器原来的值进行位与操作,就可以将特定位清零。下面我们来看一个简单的例子(假设原来 32 位寄存器中的值为:0xaaaaaaaa,我们希望将 bit8 ~bit15 清零而其他位不变,可以将这个数与0xffff00ff进行位与即可。):

代码语言:javascript
复制
 #include <stdio.h>

 int main(void) 
{
     unsigned int a=0xaaaaaaaa;
     unsigned int  b=0xffff00ff;
     unsigned int  c =a&b;
    printf("the c is 0x%x\n",c);

    return 0;   

 }

输出结果:

代码语言:javascript
复制
 the c is 0xaaaa00aa

2、特定位置1用 "|":

首先我们要明白一点:任何数,(其实就是1或者0)与1位或变成1,与0位或无变化。再明白了这一点后,我们来看一个例子(把一个寄存器值的bit4~bit7置1,其他位不变):

代码语言:javascript
复制
#include <stdio.h>

int main(void) 
{
      unsigned int a = 0x123d0cd7;
      unsigned int b = 0xf0;
      unsigned int c;

      c = a | b;
      printf("a & b = 0x%x.\n", c);  

      return 0; 

}

输出结果:

代码语言:javascript
复制
  a & b = 0x123d0cf7.

注意:bit位是用bit0开始的

3、特定位取反用 "^":

同样,首先要明白的"^"的基本用法:任何数,其实就是1或者0)与1位异或会取反,与0位异或无变化。所以,我们要构造这样一个数:要取反的特定位为1,其他位为0,然后将这个数与原来的数进行位异或即可。下面我们来看一个例子(把一个寄存器值的bit4~bit7取反,其他位不变):

代码语言:javascript
复制
#include <stdio.h>

int main(void) 
{
      unsigned int a = 0x123d0c37;
      unsigned int b = 0xf0;
      unsigned int c;

      c = a ^ b;
      printf("a & b = 0x%x.\n", c);      

      return 0; 

 }

输出结果:

代码语言:javascript
复制
  a & b = 0x123d0cc7.

4、使用移位(或者有位操作符结合)获取特定位为1或者0的二进制数

这种用法,用的比较多,比如说用"<<"(左移操作)和">>"(右移操作)移位操作来获得自己想要的目标结果,而且还会和我们上面讲的位操作符来结合使用;这里我们来看两个例子:

  • 获取bit3~bit7为1,同时bit23~bit25为1,其余位为0的数:((0x1f<<3) | (7<<23))
代码语言:javascript
复制
 #include <stdio.h>

 int main(void) 
{
      unsigned int a ;
      a = ((0x1f<<3) | (0x7<<23));
      printf("a = 0x%x.\n", a);      

      return 0; 

}

输出结果:

代码语言:javascript
复制
 a = 0x38000f8.

说明:

        这里0x1f左移3位的话就成了0xf8了,然后0x7左移23位的话,就成了 0x3800000,然后两者再进行或操作,最后结果就是0x38000f8了。

  • 这次我们要获取bit4~bit10为0,其余位全部为1的数。怎么做?利用上面讲的方法就可以:(0xf<<0)|(0x1fffff<<11),这样的话就比较不好弄了,所以这种特定位(比较少)为0而其余位(大部分)为1的数,不适合用很多个连续1左移的方式来构造,适合左移加位取反的方式来构造。我们可以这样来操作:先试图构造出这个数的位相反数,再取反得到这个数。(譬如本例中要构造的数bit4~bit10为0其余位为1,那我们就先构造一个bit4~bit10为1,其余位为0的数,然后对这个数按位取反即可)
代码语言:javascript
复制
#include <stdio.h>

int main(void) 
{
      unsigned int a;
      a = ~(0x7f<<4);                   
      printf("a = 0x%x.\n", a);  

      return 0; 

 }

     输出结果:

代码语言:javascript
复制
  a = 0xfffff80f.

5、小结

  • 如果你要的这个数比较少位为1,大部分位为0,则可以通过连续很多个1左移n位得到。
  • 如果你想要的数是比较少位为0,大部分位为1,则可以通过先构建其位反数,然后再位取反来得到。
  • 如果你想要的数中连续1(连续0)的部分不止1个,那么可以通过多段分别构造,然后再彼此位与即可。这时候因为参与位或运算的各个数为1的位是不重复的,所以这时候的位或其实相当于几个数的叠加。

三、总结:

好了,今天的分享就到这里了,更多位操作实战演示在下篇文章中继续分享。希望今天的分享对你有帮助!感谢您的收看!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 txp玩Linux 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档