admin管理员组

文章数量:1122852

C中getbits(x,p,n)函数、位操作详解

一、getbits(x,p,n)函数

函数getbits(x,p,n),返回x从p位置开始的(右对齐)n位的值;前提是最右边的一位为第0位。

例如:getbits(x,4,3)返回的是第2、3、4位;n此刻为3,计总共返回三位,p此刻为4,即返回位最左边为第四位。

 

unsigned getbits(unsigned x,int p int n)
{
return (x >> (P+1-n))&~(~0 <<n);
}

注释:设x是xxxxxxxx

~0 是11111111,左移3位,变成11111000,再取反,变成00000111

p+1-n是2,x右移2位,变成00xxxxxx

00000111

00xxxxxx

逻辑与得到红色三位,对于原x就是从第四位开始的3位.

 

#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
unsigned getbits(unsigned x, int p, int n)
{return (x >> (p + 1 - n)) & ~(~0 << n);
}
int main() {int x = 127, x1;printf("x=%x\n", x);x1 = getbits(x, 4, 3);printf("getbits(x1)=%x\n", x1);return 0;
}

 运行结果:

二、setbits(x,p,n,y)函数:

 1、编写一个函数setbits(x,p,n,y),该函数返回对x执行下列的操作的结果的值:将x中从左第p位(左边第一位为0)开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变

代码:

#include <stdio.h>unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y);int intLen(unsigned x);int main() {unsigned x = 171; // 1010 1011 --- > 101[0 1]011unsigned p = 3;unsigned n = 2;unsigned y = 38; // 0010 0110printf("result : %u \n", setbits(x, p, n, y));return 1;
}int intLen(unsigned x) {int len = 0;for (; x; x >>= 1) {len++;}return len;
}unsigned setbits(unsigned x, unsigned p, unsigned n, unsigned y) {int length_y = intLen(y);int length_x = intLen(x);if (length_x - p - n < 0) {printf("move over size by x");return 0;}if (length_y < n) {printf("move over size by y");return 0;}// int pos = p -n + 1;// unsigned cpy = y & ~ (~0 << n);// unsigned xx = (x >> pos) & (~0 << n);// return xx |= cpy;unsigned tail = length_x - (p + n);// x需要分离的子数据unsigned sub = x & ~(~0 << tail);// y 中需要替换的n位数据unsigned cpy = y & ~(~0 << n);// x向右移位,保留左边x >>= length_x - p;// x再向左移,这样最右边的n为可以为0x <<= n;//这样可以把y的拷贝值拷贝过去x |= cpy;// x再向左推进, 把刚刚的分离的n为先补0先x <<= tail;// x的分离再补充回数值x |= sub;return x;
}

链接:.html

2、setbits(x, p ,n, y),该函数返回对x执行下列操作后的结果值: 将x中从右第p位(最右边为0位)开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变。

#include<stdio.h>unsigned setbits(unsigned x, int p, int n, unsigned y)
{return x & ~(~(~0 << n) << (p+1-n)) | (y & ~(~0 << n)) << (p+1-n);
}int main()
{unsigned int x = 73;unsigned int y = 23;int p = 5;int n = 3;int r;r = setbits(x, p, n, y);printf("%d", r); //r的结果应为121return 0;
}

 

三、位操作:

1、位与&
      1)“位与”:&   “逻辑与”:&&
      2)  真值表:1&0 = 0  、0&1 = 0、0&0 = 0、1&1 = 1         只有当1与1位与时才是1,其他的值相与都是0
      3)“位与”就是把2个十六进制的数先分别转换为二进制,然后再相与。“逻辑与”就是把2个十六进制分别看成2个整体,2个整体相与。
              例子:0xA & 0xB = 0xA   //位与                               0xA && 0xB = 1 //逻辑与
                          0xA:1 0 1 0                                                   0xA = 1 (ture)
                          0xB:1 0 1 1                                                   0xB = 1 (ture)
                          位与: 1 0 1 0                                                    逻辑与 : 1

2、位或|
     1)“位或”:|    “逻辑或”:||
     2)  真值表:1|0 = 1  、0|1 = 1、0|0 = 0、1|1 = 1           只有两个0位或的时候才是0,其余的都是1
     3)  “位或”就是把2个十六进制的数先分别转换为二进制,然后再位或;“逻辑或”就是把2个十六进制分别看成2个整体,2个整体位或。
               例子:0xA | 0xB = 0xB                                                 0xA || 0xB = 1
                           0xA:1 0 1 0                                                      0xA = 1 (ture)
                           0xB:1 0 1 1                                                      0xB = 1 (ture)
                            位或: 1 0 1 1                                                      逻辑或 : 1

3、位取反 ~

     1)“位取反”:~     “逻辑取反”:!
     2)“位取反”就是把十六进制数先转换为二进制,然后把每一位取反(1取反就变为0,0取反就为1);“逻辑取反”就是把十六进制数看成一个整体,然后取反(非0的数都是为真,逻辑取反后为假;0逻辑取反为真)。
                3) 例子:0xA =  1 0 1 0                                                              0xA (非0为真(即1))
                    ~0xA =  0 1 0 1 = 0x5                                                              !0xA = 0
                   ~~0xA = 1 0 1 0 = 0xA                                                             !!0xA = 1    
    
4、位异或 ^
    1) “位异或”: ^  
    2) 真值表:1^0=1    0^1=1   0^0=0   1^1=0         两个数相等则为0,不相等则为1
    3) 例子: 66 ^ 33 = 99
                     66: 1 0 0 0 0 1 0
                     33: 0 1 0 0 0 0 1
                     99: 1 1 0 0 0 1 1

              代码:   unsigned int a = 66, b = 33;
                             unsigned int c = a^b;
                             printf("c = %d ", c);

5、左移位<<     右移位>>
        无符号数,左移时在右边补0,右移时在左边补0

二.位操作的实际应用

        一般在操作寄存器的时候使用,如32位的arm寄存器,每个位代表的pin脚不同,效果也不同。有时候你只想改变某个pin脚的值从而实现某项功能,其余pin脚保持不变,就得使用位操作,只对目标位进行操作。操作的方式是:读->改->写。不要直接给寄存器赋目标值是因为你只知道要把目标位设置为某值,但是其他的位你并不知道原本是多少,所以要先读取这个寄存器的整体值,然后再修改其中的目标位,然后再把修改后的值写到寄存器。

1)特定位清零用&
             譬如:将0xAAAAAAAA 的bit8 ~bit15清零,其他位保持不变。
             分析:[位与]任何数(0/1)与1位与时为本身,与0位与为0,所以可以用位与的方式。
                         unsigned int a = 0xAAAAAAAA;
                         unsigned int b = 0xFFFF00FF;
                         unsigned int c;
                         c = a & b;
                         printf("c = 0x%x ", c);    //c = 0xaaaa00aa

2)特定位 置1用 |
      譬如:将0xffff00ff的bit8 ~bit15置1,其他位保持不变。
      分析:位或   任何数(0/1)与1位或变为1,与0位或为本身

                  unsigned int a = 0xffff00ff;
                  unsigned int b = 0x000ff00;
                  unsigned int c;
                  c = a | b;
                  printf("c = 0x%x ", c);    // = 0xffffffff

3)特定位取反用 ^
      譬如:将0xffff00ff的bit8 ~bit15取反,其余保持不变
      分析:位异或  任何数(0/1)与1位异或会取反,与0位异或为本身
    
                  unsigned int a = 0xffff00ff;
                  unsigned int b = 0xff00;
                  unsigned int c;
                  c = a ^ b;
                  printf("c = 0x%x ", c);    // = 0xffffffff

此部分来自:

 

 

 

 

 

 

 

 

 

本文标签: C中getbits(xPn)函数位操作详解