天天看点

C语言学习之位操作一、位操作符号二、位与位操作三、运用位运算构建特定的二进制数四、练习编程

文章目录

  • 一、位操作符号
    • 1.1 位与 &
      • 1.1.1 逻辑与和位与的区别
    • 1.2 位或 |
    • 1.3 位取反 ~
      • 1.3.1 规律
    • 1.4 位异或 ^
    • 1.5 左右位移
  • 二、位与位操作
    • 2.1 寄存器操作的要求
    • 2.2 特定位置清零
    • 2.3 特定位置置1
  • 三、运用位运算构建特定的二进制数
    • 3.1为啥要构建二进制数
    • 3.2 如何用位移来构建位为1的二进制数
    • 3.3 如何用位移来构建位为0的二进制数
  • 四、练习编程
    • 4.1 给定一个整形数a,设置bit3,保证其余位置不变。
    • 4.2 给定一个整形数a,设置bit3-bit7,保证其余位置不变。
    • 4.3 给定一个整形数a,清除bit5,保证其余位置不变。
    • 4.4 给定一个整形数a,清除bit15-bit23,保证其余位置不变。
    • 4.5 给定一个整形数a,取出bit3-bit8.
    • 4.6 给一个寄存器的bit7 - bit17赋值937(其余位不受影响)
    • 4.7 给一个寄存器的bit7 - bit17中的值加上17(其余位不受影响)
    • 给一个寄存器的bit7 - bit17赋值937,bit23 - bit 27赋值9;

一、位操作符号

1.1 位与 &

位与操作符号是一个 &、两个 && 是逻辑与。

真值表:1 & 0 = 0; 1 & 1= 1; 0 & 0 = 0; 0 & 1 = 0;

只有两个都是1的情况下才能是1,其余任何情况下都是0;

1.1.1 逻辑与和位与的区别

位与:两个二进制数按照位置一一对应进行计算。(0XAA & 0XF0 = 0XA0;)

逻辑与:两个二进制数作为整体进行计算。(0XAA && 0XF0 = 1)

1.2 位或 |

位或操作符号是一个 |、两个 || 是逻辑或。

真值表:1 | 0 = 1; 1 | 1= 1; 0 | 0 = 0; 0 | 1 = 11;

只有两个都是0的情况下才是0,其余都是1;

逻辑或和逻辑与道理一样,做为整体来取或;

1.3 位取反 ~

位取反操作符号是一个 ~ ,一个 ! 是逻辑取反。

位取反就是把 二进制数从0变成1,从1变成0;

逻辑取反就是把不是0得到数变成0;把爱0变成1;

下面看代码:

#include <stdio.h>

int main()
{
        unsigned int a = 45,b = 0,c,d,e,f;
        c = ~a;
        d = !a;
        e = ~b;
        f = !b;
        printf("c = %u\n",c);
        printf("d = %u\n",d);
        printf("e = %u\n",e);
        printf("f = %u\n",f);
        return 0;
}

           

运行结果:

c = 4294967250
d = 0
e = 4294967295
f =1
           

为啥位取反会变成这么大一个数呢,

因为45的二进制是:0010 1101;

那么取反就算是 1101 0010;而编译器是32的话就是有32个二进制数,所以之前的所有0就会变成1;

C语言学习之位操作一、位操作符号二、位与位操作三、运用位运算构建特定的二进制数四、练习编程

这里面的所有1会变成0,0会变成1。

1.3.1 规律

任何非0的数按逻辑取反后再取反就会得到1;

任何非0的数按位取反后再取反就会得到他本身;

#include <stdio.h>

int main()
{
        unsigned int a = 45,c,d;
        c = ~~a;
        d = !!a;
        printf("c = %u\n",c);
        printf("d = %u\n",d);
        return 0;
}

           
c = 45
d = 1
           

1.4 位异或 ^

这个符号比较少用。

真值表: 1 ^ 1 = 0; 0 ^ 0 =0;1 ^ 0 = 1; 0 ^ 1 = 1;

两个数相同就得到0,不相同就得到1;

1.5 左右位移

对于无符号数来说:

符号 : 左位移: <<

右位移: >>

原来的二进制

左移一位后的二进制

简单理解来说,左移就是整体往左边移动。

最左边的那个0呢?移走了,先不管他。最右边需需要补上一个0。

右位移与之相反

左移一位后的二进制

简单理解来说,右移就是整体往右边移动。

最右1边的那个1呢?移走了,先不管他。最左边需需要补上一个0。

对于有符号的来说:

正数移动补0;负数移动补1;这个叫算术移位;

二、位与位操作

我这里主要是用来操作寄存器的,其余操作不做解释。采用无符号的数据

2.1 寄存器操作的要求

指定寄存器的特定端口进行操作,而不影响其他位置。

怎样去操作寄存器:

为了不影响其余的寄存器,我们会把想要修改的寄存器地址先读出来,然后就修改他的特定值,再将修改后的值整体写入寄存器中,这样就不会影响其余的值。

2.2 特定位置清零

用与符号 &

因为只有两个都是1的时候才会变成1.其余都是0;任何数与1与都是本身,和 0 与都是0;

举个例子:

进行与运算,得到的结果是

2.3 特定位置置1

用符号 |

因为1 和 什么或都是1,和0或的时候都是本身。

进行或运算,那么运算结果就是

三、运用位运算构建特定的二进制数

3.1为啥要构建二进制数

为了后期维护程序。比如运用工具(计算机、二进制转化器)可以直接让一个10进制转换化为二级制数,这样确实很方便呢,但是过了一段时间过后,我们已经记不住这个数是代表啥了。所以我们需要自己去写代码次才能让我们每次写代码的时候,明白这串二进制数的原理。

3.2 如何用位移来构建位为1的二进制数

举个例子来说

我写一个

0XF8

你一定知道这是一个16进制的数字,但是二进制时候多少呢,你不知道啊,你还得去算算。诚然现在有计算器可以帮你,但是假设你没有计算器呢。你得去用手算(我是转行的,进制转化这是一个薄弱点)我觉得麻烦,所以我的想用代码来实现一下,可以简单明了。

C语言学习之位操作一、位操作符号二、位与位操作三、运用位运算构建特定的二进制数四、练习编程

这里可以看出,我的bit3-bit7是1,其余都是0,那么是不是五个额连续的 1 左移了3位。

C语言学习之位操作一、位操作符号二、位与位操作三、运用位运算构建特定的二进制数四、练习编程

四个连续的1是不是就是 F 写成16进制就是 0XF 左移三位时候不是就是 (0XF << 3)

那我再复杂一点:bit24–bit2是1 bit4-bit7是1 这怎么办呢

bit24-bit27是4个1 bit4-bit7是4个1,那么我们也可以通过偏移的方式来写 (0XF << 4 | 0XF << 24)

让我们来检验一下:

C语言学习之位操作一、位操作符号二、位与位操作三、运用位运算构建特定的二进制数四、练习编程
#include <stdio.h>
int main()
{
        unsigned int a = 0XF;
        unsigned int b;
        b = (( a << 4) | (a << 24));
        printf("b =  0x%x.\n",b);
        return 0;
}

           

结果

是不是答案是对的,虽然我们同样也需要计算一点,但是没有那么大,只需要计算一小部分就好了。

3.3 如何用位移来构建位为0的二进制数

同样的道理,假设我们 bit4-bit7 为0,其余部分为1,我们可以先把0看成1,把1看成0;然后取反

#include <stdio.h>
int main()
{
        unsigned int a = 0XF;
        unsigned int b;
        b =  ~(a << 4);
        printf("b =  0x%x.\n",b);
        return 0;
}
           
C语言学习之位操作一、位操作符号二、位与位操作三、运用位运算构建特定的二进制数四、练习编程

如果其他位也有0的话可以 用或 连起来就行了。

四、练习编程

4.1 给定一个整形数a,设置bit3,保证其余位置不变。

unsigned int a;
a = a | (1 << 3);
           

4.2 给定一个整形数a,设置bit3-bit7,保证其余位置不变。

unsigned int a;
a = a | (0x1f << 3);
           

4.3 给定一个整形数a,清除bit5,保证其余位置不变。

unsigned int a;
a = a  & (~(1 << 5));
           

4.4 给定一个整形数a,清除bit15-bit23,保证其余位置不变。

unsigned int a;
a = a  & (~(0X1FF << 15));
           

4.5 给定一个整形数a,取出bit3-bit8.

unsigned int a = 0XC30288F8; 	//随机定义一个树
a &= (0x3 << 3); 				//保留bit3 -bit 8,其余全部置零
a = a>> 3;						//把保留的bit3-bit8移过去
           

4.6 给一个寄存器的bit7 - bit17赋值937(其余位不受影响)

unsigned int a = 0XC30288F8; 	//随机定义一个树
a &= ~(0x3FF << 7); 			//保留bit7 - bit17,其余全部置零
a |= (937 << 7);				//把赋值的数移动到bit7 - bit17
           

4.7 给一个寄存器的bit7 - bit17中的值加上17(其余位不受影响)

unsigned int a = 0XC30288F8; 	//随机定义一个树
unsigned int b;					//定义一个数用来存放值
b = a & (0x3FF << 7) ;			//保留bit7 -bit17,其余全部置零
b = b >> 7;						//读出原来 bit7 - bit17里面的数
b += 17 << 7;					//+17
a &= (~(0x3FF << 7));			//将寄存器里面的bit7 -bit17置零
a |= b;							//将b里面的数放进去
           

给一个寄存器的bit7 - bit17赋值937,bit23 - bit 27赋值9;

unsigned int a = 0XC30288F8; 	//随机定义一个数
a &= ~((0X3FF << 7) | (0X1F << 23));  //清零
a |= (937 << 7) | (9 << 23);			//赋值