C语言学习之位操作

一、位操作符号

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;
在这里插入图片描述
这里面的所有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 左右位移

对于无符号数来说:
符号 : 左位移: <<
右位移: >>
原来的二进制

0100  0001

左移一位后的二进制

1000 0010

简单理解来说,左移就是整体往左边移动。
最左边的那个0呢?移走了,先不管他。最右边需需要补上一个0。
右位移与之相反

0100  0001

左移一位后的二进制

00100 0000

简单理解来说,右移就是整体往右边移动。
最右1边的那个1呢?移走了,先不管他。最左边需需要补上一个0。

对于有符号的来说:
正数移动补0;负数移动补1;这个叫算术移位;

二、位与位操作

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

2.1 寄存器操作的要求

指定寄存器的特定端口进行操作,而不影响其他位置。
怎样去操作寄存器:
为了不影响其余的寄存器,我们会把想要修改的寄存器地址先读出来,然后就修改他的特定值,再将修改后的值整体写入寄存器中,这样就不会影响其余的值。

2.2 特定位置清零

用与符号 &
因为只有两个都是1的时候才会变成1.其余都是0;任何数与1与都是本身,和 0 与都是0;
举个例子:

0100 0011

0100 1101

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

0100 0001  

2.3 特定位置置1

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

0100 0010

0000 0000

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

0100 0010

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

3.1为啥要构建二进制数

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

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

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

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

在这里插入图片描述

四个连续的1是不是就是 F 写成16进制就是 0XF 左移三位时候不是就是 (0XF << 3)
那我再复杂一点:bit24–bit2是1 bit4-bit7是1 这怎么办呢
bit24-bit27是4个1 bit4-bit7是4个1,那么我们也可以通过偏移的方式来写 (0XF << 4 | 0XF << 24)
让我们来检验一下:

#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;
}

结果

b =  0xf0000f0.

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

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;
}
b =  0xffffff0f.

在这里插入图片描述

如果其他位也有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);			//赋值
  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永不秃头的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值