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

浅谈C语言中异或运算符的10种妙用

目录

1、前言

2、基本准则定律

3、妙用归纳

4、总结


1、前言

        C语言中异或运算符^作为一个基本的逻辑运算符,相信大家都知道其概念:通过对两个相同长度的二进制数进行逐位比较,若对应位的值不同,结果为 1, 否则结果为 0。

        但是它在实际使用中到底会有哪些应用场景或者说是有在一些编程技巧中该如何使用,本文总结归纳了一些异或运算符的编程时实用方法思路以供参考,如有其它好用的功能,也可提出一起分享。


2、基本准则定律

        首先需要明确的是异或运算的几个基本准则定律,这些准则定律为异或运算的巧妙应用提供了基础。

  • 交换律:对于任意变量 a 和 b,a ^ b 等于 b ^ a。

  • 结合律:对于任意变量 a、b 和 c,(a ^ b) ^ c 等于 a ^ (b ^ c)。

  • 自反性:任何数与自身进行异或操作结果为0,即 a ^ a = 0。

  • 零元素性质:任何数与0进行异或操作结果为自身,即 a ^ 0 = a。

  • 分配律:a ^ (b & c) = (a ^ b) & (a ^ c),其中 & 表示按位与操作。

  • 奇偶性:一个数字和1做异或运算,可以判断它的奇偶性。如果结果为0,表示这个数字是偶数,如果结果为1,表示这个数字是奇数。


3、妙用归纳

        暂归纳了10种在编程中经常遇见的异或运算使用的方法。

(1)两个值的快速比较

        例如比较两个值是否相等时,一般我们使用这个 a==b,如果两个数相等 ,a ^ b 的结果为零。

if(a^b == 0) {//a和b若相同则为true 
}

(2)数据交换

        利用异或运算的性质可以进行两个数的交换,不会利用额外的变量。

void swap()
{ a=a^b;b=b^a;a=b^a;
}

        注意利用异或运算进行数据交换有个前提:要交换的两个数必须在在不同的内存,不然会出现问题。如果 a 和 b 是同一个地址呢?比如,我们调用的是 swap(a[i], a[j]),当 i == j时,利用异或运算进行数据交换是错误的。

        在这种情况下,我们第一步做的 a ^= b,实际上就是 a[i] ^= a[i]。这将直接让a[i]中的元素等于0,而丢失原本存在a[i]中的元素。后续这个元素就再也找不回来了。针对这个问题解决方案是在做这个交换之前,判断一下 a 和 b的地址是否相同。也可以把逻辑改变为,判断一下a和b是否相同。如果相同,则什么都不做。

(3)加减法

        如二进制加法01 + 01 = 10,而异或运算是01 ^ 01 = 00,它其实做了加法,但高位不进位,所以异或又称不进位加法。

        如二进制减法10 - 01 = 01,而异或运算是10 ^ 01 = 11,也可以看做个位0向高位借了一个1当2来用,但高位不减1,所以异或也可以称为不退位减法。

        利用异或的这个特性,只要再解决一下进位和退位问题,就可以实现加减法了。这也是为什么CPU里面都是做位运算的逻辑门电路,却能实现数值计算。

int plus(int a, int b) {int sum, addition;while (b != 0) {// 加法(未考虑进位)sum = a ^ b;// 进位值,二进制中1 + 1的场景才会进位,//a & b只有两个都为1,结果才是1,左移一位,就是进位值了addition = (a & b) << 1;// 赋值,下次循环将进位加到a里面来,直到进位等于0a = sum;b = addition;}return a;
}int subtraction(int a, int b){int sum, abdication;while (b != 0){// 减法(未考虑退位)sum = a ^ b;// 退位值,二进制中0 - 1的场景才会退位,//~a & b只有a=0,b=1,结果才是1,左移一位,就是退位值了abdication = (~a & b) << 1;// 赋值,下次循环将退位再从a中减掉,直到退位等于0a = sum;b = abdication;}return a;
}

(4)数据备份

        使用异或也可以很容易实现多个数据的互相备份,假如有数据a、b、c,则d = a ^ b ^ c,然后把数据d备份下来。

当a丢失时,可使用d ^ b ^ c来恢复
当b丢失时,可使用d ^ a ^ c来恢复
当c丢失时,可使用d ^ a ^ b来恢复

        由此可见备份了一份数据d后,丢失了其他任何一个数据,都可以通过备份数据与其它数据异或恢复回来,磁盘阵列技术raid5的数据备份原理,用的就是这个特性。

(5)数据加解密

        在例如通信时需要对数据使用简单的加解密方法时,使用异或操作可以进行明文数据的加解密,。比如明文数据是message,密钥是key,加密后的数据是secret,确保通信发送方和通信接收方都存储了相同的key,key可以使用rand()生产一串随机数,则举例说明:

// 加密
secret = message ^ key
0x2C0E = 0x89AB ^ 0xA5A5
// 解密
message = secret ^ key
0x89AB = 0x2C0E ^ 0xA5A5

        美国数学家香农证明了只要满足以下两个条件,异或加密是无法破解的。

  • key的长度大于等于message。

  • key必须是一次性的,且每次都要随机产生。

        理由很简单,如果每次的 key 都是随机的,那么产生的secret具有所有可能的值,而且是均匀分布,无法从secret看出 message 的任何特征。也就是说,它具有最大的"信息熵",因此完全不可能破解。这被称为异或的"完美保密性"。为了让异或加密更可靠,可以添加一些其他操作,例如对数据进行循环位移或取反的操作。

(6)数据奇偶数判断

        由于异或运算要先转化为二进制数,而偶数的二进制数的最后一位必定是0,奇数的二进制数的最后一位必定是1。

        因此,要判断的数与1异或得到的结果 - 要判断的数==1,说明该数是偶数,反之是奇数!

int a = 12345; //a=123456
if ((a ^ 1) - a == 1) {"是偶数!";
} else {"是奇数!";
}

(7)出现奇偶次的找数问题

        一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数?

        分析:利用异或性质a ^ a=0,则出现偶数的数字相异或为0,而出现奇数次的异或结果为本身,那么,将所有的数异或后,就是要找的这个出现奇数次的数。

int ReOddNum1(int arr[], int len)
{int re = arr[0];for (int i=1;i<len;i++){re = arr[i] ^ re;}return re;
}

        一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数?

        step1:将所有数异或,得到re=a^b;

        step2:提取re最右侧的“1”(取反,+1,自身相与);

        step3:将所有该位为“1”的数相异或,得到的数便为a或者b;

        step4:再次相与两个结果,得到另一个数。

int* ReOddNum2(int arr[], int len)
{int re = arr[0];int rr[2] = { 0,0 };//第一步:将所有数异或,得到a^bfor (int i = 1; i < len; i++){re = arr[i] ^ re;}//第二步:提取re最右侧的“1”(取反,+1,自身相与)int rightone = re&(~re + 1);//第三步:将所有该位为“1”的数相异或,得到的数便为a或者bint re1 = 0;for (int i = 0; i < len; i++){if ((arr[i]&rightone)!=0){re1 = arr[i] ^ re1;}    }rr[0] = re1;//第四步:再次相与两个结果,得到另一个数rr[1] = re1^re;return rr;  
}

(8)奇偶校验

        首先先看一个例子理解下:判断一个二进制数中1的数量是奇数还是偶数。

        求10110101中出现1的数量是奇数还是偶数;可将10110101逐位异或操作,结果为1就是奇数个1,结果为0就是偶数个1。

        奇校验:原始码+1位校验位,总共有奇数个1;

        偶校验:原始码+1位校验位,总共有偶数个1。

        比如为原始码添加奇偶校验位:

        原始码:1101010

        判断1的个数是否为偶数:1^1^0^1^0^1^0=0,因为逐位异或的结果为0,所以1的个数为偶数,奇校验则在原数据末尾添1,变成11010101;偶校验则在原数据末尾添0,变成11010100。

(9)对某些特定的位翻转

        由于不管是0或者1与1做异或操作后将得到原值的相反值,因此当我们需要翻转一个整数的某些位时,我们可以使用位异或运算来实现掩码操作,将对应的数据位进行翻转。

//定义一个整数n
int a = 0x0f; //二进制表示为00001111
//如果需要翻转a的第4和第5位,则定义掩码mask
int mask = 0x18; //二进制表示为00011000
//使用位异或运算翻转n的第3位和第4位
n = n ^ mask; //结果为二进制表示为00010111

        在单片机编程中对GPIO输出控制LED的闪烁原理也是如此,定义了一个宏,直接通过GPIOA口对ODR寄存器进行操作,异或PIN2的位。实现引脚PA2输出高低电平的翻转控制LED闪烁。

// PA2引脚输出电平翻转
#define LED_TOGGLE() GPIOA->ODR ^= GPIO_PIN_2

(10)数据符号判断

        例如判断两个int32类型的数据的符号是否相同,其中31是符号位的偏移量:

if (((a ^ b) >> 31) & 1) {"符号不相同!";
} else {"符号相同!";
}

4、总结

        总之,异或运算是一种重要的二进制运算,在实际代码编程中有着广泛的应用。需要深刻的去理解异或运算符的几条基本准则定律,就能够快速地完成数字的交换、计算、去重等操作,为我们在功能开发中提供便利。

        小tips:归根到底在布尔代数中,其实只需要与、或、非运算就可以实现所有其它运算,所以异或运算实际可以通过与、或、非实现,最直观的表示方式如下:

a ^ b = (~a & b) | (a & ~b)  

↓↓↓更多技术内容和书籍资料获取,入群技术交流敬请关注“明解嵌入式”↓↓↓ 

相关文章:

浅谈C语言中异或运算符的10种妙用

目录 1、前言 2、基本准则定律 3、妙用归纳 4、总结 1、前言 C语言中异或运算符^作为一个基本的逻辑运算符&#xff0c;相信大家都知道其概念&#xff1a;通过对两个相同长度的二进制数进行逐位比较&#xff0c;若对应位的值不同&#xff0c;结果为 1, 否则结果为 0。 但是…...

Canal--->准备MySql主数据库---->安装canal

一、安装主数据库 1.在服务器新建文件夹 mysql/data&#xff0c;新建文件 mysql/conf.d/my.cnf 其中my.cnf 内容如下 [mysqld] log_timestampsSYSTEM default-time-zone8:00 server-id1 log-binmysql-bin binlog-do-db mall # 要监听的库 binlog_formatROW2.启动数据库 do…...

vs配置opencv运行时“发生生成错误,是否继续并运行上次的成功生成”BUG解决办法

vs“发生生成错误&#xff0c;是否继续并运行上次的成功生成” 新手在用vs配置opencv时遇到这个错误时&#xff0c;容易无从下手解决。博主亲身经历很有可能是release/debug模式和配置文件不符的问题。 在配置【链接器】→【输入】→【附加依赖项】环节&#xff0c;编辑查看选择…...

Dryad Girl Fawnia

一个可爱的Dryad Girl Fawnia的三维模型。她有ARKit混合形状,人形装备,多种颜色可供选择。她将是一个完美的角色,幻想或装扮游戏。 🔥 Dryad Girl | Fawnia 一个可爱的Dryad Girl Fawnia的三维模型。她有ARKit混合形状,人形装备,多种颜色可供选择。她将是一个完美的角色…...

内存相关知识(新)

基本概念 内存层次结构&#xff1a;内存层次结构是一种层次化的存储设备结构&#xff0c;它包括寄存器、缓存、主存和辅助存储器。每一层次的存储设备都有不同的速度、容量和成本。 内存单元&#xff1a;内存被划分为一系列连续的内存单元&#xff0c;每个单元都有一个唯一的地…...

C++从入门到精通——static成员

static成员 前言一、static成员概念例题 二、 static成员的特性特性例题静态成员函数可以调用非静态成员函数吗非静态成员函数可以调用类的静态成员函数吗 前言 一、static成员 概念 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之…...

【K8S:初始化】:执行kubeadm显示:connection refused.

文章目录 [root10 kubernetes]# kubeadm init --kubernetes-versionv1.23.0 --image-repositoryregistry.aliyuncs.com/google_containers --apiserver-advertise-address192.168.56.104 [init] Using Kubernetes version: v1.23.0 [preflight] Running pre-flight checks [pre…...

msvcp140_1.dll是什么?找不到msvcp140_1.dll丢失解决方法

msvcp140_1.dll 文件是一个与 Microsoft Visual C 2015 Redistributable 相关的动态链接库&#xff08;DLL&#xff09;&#xff0c;它在 Windows 系统中扮演着重要角色&#xff0c;尤其对于那些依赖于 Visual C 运行时环境的应用程序和游戏来说。以下是关于 msvcp140_1.dll 文…...

【Java探索之旅】掌握数组操作,轻松应对编程挑战

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、数组巩固练习1.1 数组转字符串1.2 数组拷贝1.3 求数组中的平均值1.4 查找数组中指…...

深入理解同步与异步编程及协程管理在Python中的应用

文章目录 1. 同步与异步函数的对比1.1 同步函数1.2 异步函数1.3 对比 2. 管理多个协程与异常处理2.1 并发执行多个协程2.2 错误处理2.3 任务取消 本文将探索Python中同步与异步编程的基本概念及其区别。还会详细介绍如何使用asyncio库来有效管理协程&#xff0c;包括任务的创建…...

Win10本地更新无法升级win11 的0x80080005解决方法

Win10本地更新无法升级win11 Visual Studio 2022 运行项目时&#xff0c;本文提供了错误“指定的程序需要较新版本的 Windows”的解决方法。 更新时提示&#xff1a;0x80080005 解决方法 1、下载Windows11InstallationAssistant.exe 【免费】Windows11InstallationAssista…...

互联网轻量级框架整合之MyBatis核心组件

在看本篇内容之前&#xff0c;最好先理解一下Hibernate和MyBatis的本质区别&#xff0c;这篇Hibernate和MyBatis使用对比实例做了实际的代码级对比&#xff0c;而MyBatis作为更适合互联网产品的持久层首选必定有必然的原因 MyBatis核心组件 MyBatis能够成为数据持久层首选框&a…...

springboot websocket 持续打印 pod 日志

springboot 整合 websocket 和 连接 k8s 集群的方式参考历史 Java 专栏文章 修改前端页面 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Java后端WebSocket的Tomcat实现</title><script type"text/javasc…...

C代码编译过程与进程内存分布

C代码编译过程 在这篇文章中&#xff0c;我们将探讨C语言代码的编译流程以及进程在运行时的内存布局。编译过程通常包括几个关键步骤&#xff1a;预处理、编译、汇编和链接。 预处理阶段主要是处理源代码文件中的宏定义、头文件包含和条件编译指令。在此阶段&#xff0c;编译…...

Windows 部署ChatGLM3大语言模型

一、环境要求 硬件 内存&#xff1a;> 16GB 显存: > 13GB&#xff08;4080 16GB&#xff09; 硬盘&#xff1a;60G 软件 python 版本推荐3.10 - 3.11 transformers 库版本推荐为 4.36.2 torch 推荐使用 2.0 及以上的版本&#xff0c;以获得最佳的推理性能 二、部…...

JS相关八股之什么是事件循环

在JavaScript中&#xff0c;“事件循环”&#xff08;Event Loop&#xff09;是一个非常重要的概念&#xff0c;它是指JavaScript引擎如何在单线程中处理异步操作的机制。单线程意味着在任意时刻&#xff0c;JavaScript代码只能执行一个任务。 一.事件循环的工作流程大致如下&…...

SpringCloud集成Skywalking链路追踪和日志收集

1. 下载Agents https://archive.apache.org/dist/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz 2. 上传到服务器解压 在Spring Cloud项目中&#xff0c;每部署一个服务时&#xff0c;就拷贝一份skywalking的agent文件到该服务器上并解压。不管是部署…...

HTTP 域名和主机是一回事吗?有了主机和域名,如何建站?

域名不等于主机名&#xff0c;例如baidu.com是一个权威域的域名&#xff0c;但是根本没有一个主机的名字叫做baidu.com,但是dns.baidu.com就是一个主机名&#xff0c;它就是负责baidu.com的服务器的主机名&#xff0c;www.baidu.com也是一个主机名,它是百度web服务器的主机名。…...

运营干货:四个技巧掌握爆款选题方法

在运营工作中&#xff0c;选题是一项至关重要的工作&#xff0c;选对了一个热门话题&#xff0c;就能吸引大量用户的关注和互动&#xff0c;从而取得更好的运营成果。 今天&#xff0c;就给大家分享四个爆款选题方法&#xff0c;让大家的运营更上一层楼&#xff01; 第一种&a…...

柯桥商务口语之怎么样说英语更加礼貌?十个礼貌用语get起来!

当你在国外需要帮助的时候&#xff0c;这些礼貌用语真的是能够帮到你的哦 1.Would/Could you help me? 你可帮助我吗&#xff1f; 相信有些人想请求帮助的时候&#xff0c;一开口就用Can you&#xff0c;这个用在朋友或者熟人上面当然是没有问题的&#xff0c;但是如果是向…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...