zoukankan      html  css  js  c++  java
  • 带参数的宏定义实战篇

    前言:最近在看一位叫朱有鹏大神的视频,讲的甚好。应此,我的感悟也因此被激发,准备针对朱老师将的内容,结合自己的理解,写一个系列的笔记博客~~大家可以去www.zhulaoshi.org观看视频~~

     

     

     

    要想理解此文,需要熟悉位操作的方法,您可能需要先阅读这篇文章—:《arm学习——有关位操作的总结》

     

    我们用带参数的宏定义,来实现一些有用的位操作。

    1、直接用宏来置位、复位(最右边为第0位)

    #define SET(x,n) ( (x) | ( 1U << (n) ) ) 

    #define CLEAR(x,n) ( (x) & ~( 1U << (n) ) ) 

    2、截取变量的部分连续位。例如:变量0x88, 也就是10001000b,若截取第7~5位,则值

    为:100b = 4 

    我们给出开头:

    #define GETBITS(x, high, low) 宏体

     

        这其实是想读取某个变量的连续几位,在《arm学习——有关位操作的总结》提到过,“读”在乎的是

    不变的位。我们可以利用&的特性——任何数(0或1)和1与(&),结果不变;和0与(&)结果为0.

    那么我们想读x变量的取7~5位,就可以这么写x = (x & (7<<5))>> 5

    测试程序:

    int x = 0xe0;//0b1110_0000

    x = (x & (7<<5))>> 5;

    printf("x = %d ",x);//结果为7,及0b111

        那么说明结果是对的,那么接下来。我们如何用带参数的宏定义实现呢?实现的关键是

    实现随意制造连续的1.如上题中,需截取7~5位及3位,于是我们直接给出7,因为7用二进制

    表示就是111.

        首先想到的方法是寻找位数3和7的关系,容易得出2的3次方减1等于7,进而得到

    “2的n(位数)次方减1 = 一个进制数”,如需要4个并排的1:1111,那么就是2的4(位数)次方减1= 15;

    这样确实可以确立关系,但是未免也过于复杂。

        其次,想到直接通过平移的方式,先构造出全为1的数,然后通过左移和右移动把不需要的1移

    出去。但是需要注意的是,对于一个无符号数来说,不管是左移还是右移都是补0的,而不是补1.

        我们就利用这个特性来实现:假如我想得到3个1:111,那么我们一个全1的数左移3位,那么

    我们得到一个左边3位为0,其余位都为1的数...1111_1000,接着将这个数按位取反,我们就得到

    了3个1:111。真是巧妙。通过 ~(~(0U)<<(high-low+1))就能得到想要的“并排的1”。

    (x & (7<<5))>> 5,接着将其带入到这个特殊式,让其成为一般式即可(该加上的括号还得加):

    ((x & (~(~(0U)<<(high-low+1))<<low))>> low) ,这里其实还可以去掉一个括号

    ((x & ~(~(0U)<<(high-low+1))<<low)>> low),原因就是~优先级高于&,其实我还是喜欢加上这个括号,

    更便于理解。

     

        最后呢,还是在把x high low之类的再扩上一层,得到最终的结果

    #define GETBITS(x, high, low)  (((x) & (~(~(0U)<<((high)-(low)+1))<<(low)))>> (low))

    程序验证:

    int x = 0xfc;

    x = GETBITS(x,7,5);

    printf("x = %d ",x);

     

    总结:有了这个几个宏,以后ARM中操作寄存器就非常方便了~~

    #define SET(x,n) ( (x) | ( 1U << (n) ) )             //设置某个寄存器的某位为1(最右边为第0位)

    #define CLEAR(x,n) ( (x) & ~( 1U << (n) ) )   //设置某个寄存器的某位为0(最右边为第0位)

    #define GETBITS(x, high, low)  (((x) & (~(~(0U)<<((high)-(low)+1))<<(low)))>> (low))  //读取某个寄存器的 high~low(最右边为第0位)

     

     

    //------分析过程-----朱老师笔记原文(稍有修改)-------

    看到这么复杂的宏解析方法也很重要:首先找到配对的括号,一步步逐层分析:

    //-------该部分摘抄自朱老师大课堂笔记,稍有改动----

    复杂宏怎么分析:

    ((x & ~(~(0U)<<(high-low+1))<<(low))>> (low))

    第一步,先分清楚这个复杂宏分为几部分:2部分

    (x & ~(~(0U)<<(high-low+1))<<(low)) >> (low)

     

     

    第二步,继续解析剩下的:又分为2部分

    x & ~(~(0U)<<(high-low+1))<<(low)

     

     

    第三步,继续分析剩下的:

    ~(~(0U)<<(high-low+1))<<(low) 

    这个分析时要搞清楚第2坨到底应该先左边取反再右边<<还是先右边<<再左边取反。

    解法:第一,查C语言优先级表;第二,自己实际写个代码测试。

    说明这个式子应该是~(~(0U)<<(high-low+1))<<(low) ,这就又分为2部分了

    //------------------------------------------------

  • 相关阅读:
    创建授权SQL mysql数据库命令
    [mysql] 无法通过insert 创建用户ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value
    MySql 用户管理 中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束):
    mysql 导出数据到文件数据异常 ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
    tab切换 js制作 index和this的应用
    mysql中 where in 用法详解
    Mysql Join语法解析与性能分析
    Java 导入导出Excle表格 两种方式
    SQLyog 快捷键
    DnCNN-Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising
  • 原文地址:https://www.cnblogs.com/douzi2/p/4934112.html
Copyright © 2011-2022 走看看