当前位置: 首页 > news >正文

C语言——位运算

位运算

针对数据的二进制位进行的相关操作,位运算在嵌入式开发领域有着非常重要的应用。

位运算常用的运算符

注意:参与位运算的运算量只能是整型或者字符型,不能是实型。

位运算符的运算规则

&:按位与

运算规则:对于左右操作数,只有相应二进制位数据都为1时,结果数据对应位数据为1。简单来说:

你为1,我为1,结果就是1,否则0来凑

作用:

1.获取某二进制位数据

2.将指定二进制位数据清零

3.保留指定位

|:按位或

运算规则:对于左右操作数,只要相应二进制位数据有一个为1,结果数据对应为数据为1。简单来说:

你为1,或者 我为1,结果就是1

作用:

1.置位某二进制位数据

^:按位异或

运算规则:对于左右操作数,只要相应二进制位数据相同,结果数据对应位数据为0,不同为1。简单来说:

你我相同,结果为8;你我不同,结果为1

作用:

1.翻转

2.值交换

~:按位取反

运算规则:原操作数据将相应二进制位数据:

0变1,1变0

按位左移(<<)

运算规则:原操作数所有的二进制位数向左移动指定位:移出的数据舍弃,右边用0补全

注意:
1.如果移出的高位都是0,我们可以这样理解:

a<<n,可以看做:a * 2^n2.        如果移出的高位包含1,我们是不能使用以上计算方式的。

按位右移(>>)。

运算规则:原操作数所有的二进制位数据向右移动指定位,移出的数据舍弃:

如果操作数是无符号数,左边用0补全;

如果操作数是有符号数,左边用什么去补全,取决于计算机系统:

        逻辑右移:用0补全

        算数右移:用1补全

大部分情况下,系统采用算数右移

位运算赋值符

运算符:&=, |=, >>=,<<=,^=

举例:

a &= b 相当于 a = a & b2

a <<= 2相当于 a = a << 2

不同长度数据进行位运算

        如果两个数据长度不同(例如long型和short型),进行位运算时(如a & b,而a为long型,b为short型),系统会将二者按右端对齐。

如果b为正数,则左侧16位补满0;

如果b为负数,左端应补满1;

如果b为无符号整数型,则左侧添满0。

位运算符的应用场景

注意:以下所有场景的n都是从右侧开始计数,从0开始

1. 将某个数据从右侧(低位)指定的二进制位(n1,n2,n3...)清零

        公式:

a &= ~(1(n1-1) | 1(n2-1) | 1(n3-1),...);

        案例:

char a = 1011 0110;// 将它的1,3,5位清零;结果为:a = 1010 0010
// 可以通过公式运算得到
a &= ~(1(1-1) | 1(3-1) | 1(5-1)); // 此刻 a的值就是1010 0010

2. 获取某个数据指定的二进制位(n)上的数据是0还是1

        公式:

(a & (1 n)) >> n

3. 将某个数据从右侧指定的二进制位(n1,n2,n3)设置为1

        公式:

a |= (1 n1 | 1 n2 | 1 n3,...);

        举例:

a = 1010 1010; // 2,4,6设置为1,1111 1110
a |= (1 << 2 | 1 << 4 | 1 << 6);

4. 将某个数据指定的二进制位(n)翻转

        公式:

a ^= (1 n)

        举例:

a = 1010 1010; // 将第2位进行翻转,1010 11102a ^= (1 2);

位段/位域

概念

在结构体中,以位(bit)为单位的成员,称为位段或位域

位段本质是结构体的成员,可以通过数字指明它所占内存空间的大小(以bit为单位)

说明

// eg: STM32中电源控制寄存器(PWR_CR)
struct PWR
{unisgned int ldps : 1;unsigned int pdds : 1;unsigned int cwuf : 1;unsigned int csbf : 1;unsigned int pvde : 1;unsigned int pls : 3;unsigned int pvde : 1;unsigned short d ;
};
struct Stu stu = {1,0,1,1,1,7,1};
// 应用:
// 方便给寄存器中的某些数据位设置数据

注意

        位段不能取地址

struct S
{char a : 2;unsigned char b : 4;
};
struct S s;
printf("%p\n", &s);   //s是结构体变量,可以取地址
printf("%p\n", &(s.a)); //s.a是结构体成员位段a,不能对它取地址

        给位段成员赋值时,不能超出成员所占内存

struct S
{char a : 2;unsigned char b : 4;unsigned char c : 5;
};
struct S s = {1, 3};
s.a = 1; //a占两个bit位,并且是有符号数,它能被赋值为-2, -1, 0, 1,2, 3; 除此之外的都会报错
s.b = 10; //b占4个bit位,并且是无符号数,它的取值范围为:[0,15]; 如果取值是[-8,15]编译正常,只是-8
在输出是值为15
s.c = 20; //c占5个bit位,并且是无符号数,它的取值范围为:[0,31];如果取值是[-16,31]编译正常,只
是-16在输出是值为31

        位段成员定义时不能是浮点数; 只能是整型和字符型或者他们的无符号形式

struct A
{int a:2;unsigned char b:4;float c:4;  //错误,位段成员不能定义成float或者double6};

        一个位段必须存放在一个内存单元中,不能跨两个单元

struct A
{char a:7;   //a在一个内存单元中,剩余一个bit位char b:7;   //b得从下一个内存单元开始,因为上一个内存单元剩余一个bit,放不下7个bitchar c:3;   //c得从下一个内存单元开始,因为上一个内存单元剩余一个bit, 放不下3个bitchar d:3;   //d和c可以在同一个内存单元中,因为c只占了3个还剩余5个bit,能够放下d的3个bit不用跨内存单元
};

        位段的长度不能大于存储单元的长度

struct A
{char a:1;char b:8; //一个char占一个字节,最大分配8个bit位char c:9; //一个char占一个字节,最大分配8个bit位,如果分配9个就是错误的,无法通过编译   
};

        如果一个位段要从另一个存储单元开始,可以在它前面定义一个匿名成员占0个字节

struct A
{char a:1;char b:2;   //a,b总共占3个字节,在一个内存单元中就可以存放,所以不用跨内存单元char :0;    //匿名成员,占0个字节char c:2;   //c不和a,b在一个字节(内存单元)中,而是在另外一个字节(内存单元)中
};

说明:

如果成员c上面没有匿名成员,c就和a,b在同一个字节(同一个内存单元中)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • linux系统使用 docker 来部署web环境 nginx+php7.4 并配置称 docker-compose-mysql.yml 文件
  • 【第一章概述—计算机中的数制】非十进制数到十进制数的转换,八进制转十进制,16进制转十进制。十进制转8进制,十进制转16进制
  • SSRF漏洞实现
  • Flask返回Json格式字符,中文导致unicode乱码问题
  • Unity URP Shader 修改深度让人物不再被地面遮挡
  • 数论之组合数
  • git cherry-pick 合并多个提交
  • Go 调用Rust函数
  • 浅谈线性表——链表
  • AI编程简介
  • 【第69课】Java安全JWT攻防Swagger自动化算法签名密匙Druid未授权
  • java-Mybatis框架
  • MFC程序设计(一) MFC框架
  • 23种设计模式详细知识点(软件设计师)
  • 【工控】线扫相机小结
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 【EOS】Cleos基础
  • Angular 2 DI - IoC DI - 1
  • Effective Java 笔记(一)
  • java2019面试题北京
  • jquery ajax学习笔记
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • MySQL数据库运维之数据恢复
  • PhantomJS 安装
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • 分类模型——Logistics Regression
  • 高性能JavaScript阅读简记(三)
  • ------- 计算机网络基础
  • 看域名解析域名安全对SEO的影响
  • 前言-如何学习区块链
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 使用API自动生成工具优化前端工作流
  • 手机端车牌号码键盘的vue组件
  • 推荐一个React的管理后台框架
  • 字符串匹配基础上
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​MySQL主从复制一致性检测
  • ​水经微图Web1.5.0版即将上线
  • # Redis 入门到精通(九)-- 主从复制(1)
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • (04)odoo视图操作
  • (20)docke容器
  • (rabbitmq的高级特性)消息可靠性
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (汇总)os模块以及shutil模块对文件的操作
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (十)T检验-第一部分
  • (十七)Flink 容错机制
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (转)ABI是什么
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • . NET自动找可写目录
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET 5种线程安全集合