C语言之位运算/原码/反码/补码、进制间的转换、常规应用

2024-05-31 10:38

本文主要是介绍C语言之位运算/原码/反码/补码、进制间的转换、常规应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

所谓位运算,就是对一个比特(Bit)位进行操作。比特(Bit)是一个电子元器件,8个比特构成一个字节(Byte),它已经是粒度最小的可操作单元了。

****进制间的转换:

 16进制转换成10进制:例如0xff:  15*16^1+15*16^0=255。

10进制转换成16进制:用十进制数整除以16,然后取余数,直到商为0则停止转换。余数可以是0~15中的某一个数,其中0~9不用改变,10~15则分别用A~F表示。最先得到的余数是最低位,最后得到的是最高位,由高到低排列得到16进制数(逆序)。(也可以先八10进制转换成二进制,再把二进制转换成16进制.)

 

二进制转成10进制:数字中所有位*本位的权重然后求和,注意如果二进制有小数部分,小数部分的权重指数是负的;例如10101.101=1*2^4+0*2^3+1*2^2+0*2^1+1*2^0+1*2^-1+0*2^-2+1*2-3=21.625,

10进制转换二进制:将10进制数字不断除以2直到商为零,然后将余数由下至上依次写出(逆序),即可得到该数字的二进制表示.

10进制小数转换成二进制:十进制小数转R进制小数(其他进制方法类似),方法为乘R取整,每次乘以相应之后基数后取结果的整数部分即可,直到小数部分为0,但是并非所有的十进制小数都能完全转化为R进制小数,这时就需要根据要求的精度值,类似四舍五入(比如二进制0舍去,1进位)。例如:

0.625*2=1.25  整数1

0.25*2=0.5      整数0

0.5*2=1.0         整数1

结果按顺序排列得到0.101;

 

二进制转换成八进制:从右向左,每三位一组(不足三位的在左侧补0),转换成8进制;

8进制转换成二进制:用3位二进制代码替换每一位8进制;

 

二进制转行成16进制:从右向左,每四位一组(不足四位的在左侧补0),转换成16进制;

16进制转换成二进制:用四位二进制代码替换每一位16进制;

 

负数的16进制的表示方法:首先应该将其表示成二进制形式,然后变反码,再变补码,然后把补码每四位转换成16进制。

以-1来说:将-1表示成4位二进制数(求补码),就是1111(此时将1111当成有符号数),然后直接化16进制数;-1的一位有符号16进制数就是 F.
-10的8位有符号二进制数为11110110(补码表示),化为2位有符号的16进制数FA.

如何判断一个16进制数是正是负?
看有没有指明这个16进制数是否为有符号数,如果题目说明为无符号数,则表示正数. 如果为有符号数,就要判断符号的正负:将16进制数的最高位化为4位二进制数,如果所化的二进制数的最高位为1就表示负数,为0就表示正数.
例 FA 为有符号的16进制数,F为FA的最高位,化为二进制数为1111,而1111的最高位为1,就表示FA是个负数.FA化为10进制数就为 -10

负数的二进制表示:最左侧位0表示整数,1表示负数;

溢出:https://www.cnblogs.com/Jamesjiang/p/8947252.html

 

***常规使用:

为什么要byte要和0xff进行按位与运算?

当一个byte会转换成int时,由于int是32位,而byte只有8位这时会进行补位,例如补码11111111的十进制数为-1,转换为int时变为11111111 11111111 11111111 11111111,即0xffffffff但是这个数是不对的,这种补位就会造成误差。和0xff相与后,高24比特就会被清0了,结果就对了。

 

C语言提供了六种位运算符:

运算符 & | ^ ~ << >>

说明 按位与 按位或 按位异或 取反 左移 右移

 

*****************按位与运算(&)

一个比特(Bit)位只有 0 和 1 两个取值,只有参与&运算的两个位都为 1 时,结果才为 1,否则为 0。例如1&1为 1,0&0为 0,1&0也为 0,这和逻辑运算符&&非常类似。

 

C语言中不能直接使用二进制,&两边的操作数可以是十进制、八进制、十六进制,它们在内存中最终都是以二进制形式存储,&就是对这些内存中的二进制位进行运算。其他的位运算符也是相同的道理。

 

例如,9 & 5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)

& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001  (1 在内存中的存储)

也就是说,按位与运算会对参与运算的两个数的所有二进制位进行&运算,9 & 5的结果为 1。

 

又如,-9 & 5可以转换成如下的运算:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-9 & 5的结果是 5。

&是根据内存中的二进制位进行运算的,而不是数据的二进制形式;其他位运算符也一样。以-9&5为例,-9 的在内存中的存储和 -9 的二进制形式截然不同:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

-0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (-9 的二进制形式,前面多余的 0 可以抹掉)

 

按位与运算通常用来对某些位清 0,或者保留某些位。例如要把 n 的高 16 位清 0 ,保留低 16 位,可以进行n & 0XFFFF运算(0XFFFF 在内存中的存储形式为 0000 0000 -- 0000 0000 -- 1111 1111 -- 1111 1111)。

 

【实例】对上面的分析进行检验。

#include <stdio.h>

int main(){

    int n = 0X8FA6002D;

    printf("%d, %d, %X\n", 9 & 5, -9 & 5, n & 0XFFFF);

    return 0;

}

运行结果:

1, 5, 2D

 

 

**********按位或运算(|)

 

参与|运算的两个二进制位有一个为 1 时,结果就为 1,两个都为 0 时结果才为 0。例如1|1为1,0|0为0,1|0为1,这和逻辑运算中的||非常类似。

 

例如,9 | 5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)

|   0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1101  (13 在内存中的存储)

9 | 5的结果为 13。

 

又如,-9 | 5可以转换成如下的运算:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

|   0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-----------------------------------------------------------------------------------

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

-9 | 5的结果是 -9。

 

按位或运算可以用来将某些位 置 为1,或者保留某些位。例如要把 n 的高 16 位置 1,保留低 16 位,可以进行n | 0XFFFF0000运算(0XFFFF0000 在内存中的存储形式为 1111 1111 -- 1111 1111 -- 0000 0000 -- 0000 0000)。

 

【实例】对上面的分析进行校验。

#include <stdio.h>

int main(){

    int n = 0X2D;

    printf("%d, %d, %X\n", 9 | 5, -9 | 5, n | 0XFFFF0000);

    return 0;

}

运行结果:

13, -9, FFFF002D

 

*********按位异或运算(^)

 

参与^运算两个二进制位不同时,结果为 1,相同时结果为 0。例如0^1为1,0^0为0,1^1为0。

 

例如,9 ^ 5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)

^  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1100  (12 在内存中的存储)

9 ^ 5的结果为 12。

 

又如,-9 ^ 5可以转换成如下的运算:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

^  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-----------------------------------------------------------------------------------

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0010  (-14 在内存中的存储)

-9 ^ 5的结果是 -14。

 

按位异或运算可以用来将某些二进制位反转。例如要把 n 的高 16 位反转,保留低 16 位,可以进行n ^ 0XFFFF0000运算(0XFFFF0000 在内存中的存储形式为 1111 1111 -- 1111 1111 -- 0000 0000 -- 0000 0000)。

 

【实例】对上面的分析进行校验。

#include <stdio.h>

int main(){

    unsigned n = 0X0A07002D;

    printf("%d, %d, %X\n", 9 ^ 5, -9 ^ 5, n ^ 0XFFFF0000);

    return 0;

}

运行结果:

12, -14, F5F8002D

 

 

**************取反运算(~)

 

取反运算符~为单目运算符,右结合性,作用是对参与运算的二进制位取反。例如~1为0,~0为1,这和逻辑运算中的!非常类似。。

 

例如,~9可以转换为如下的运算:

~ 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)

-----------------------------------------------------------------------------------

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0110  (-10 在内存中的存储)

所以~9的结果为 -10。

 

例如,~-9可以转换为如下的运算:

~ 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1000  (9 在内存中的存储)

所以~-9的结果为 8。

 

【实例】对上面的分析进行校验。

#include <stdio.h>

int main(){

    printf("%d, %d\n", ~9, ~-9 );

    return 0;

}

运行结果:

-10, 8

 

 

************左移运算(<<)

 

左移运算符<<用来把操作数的各个二进制位全部左移若干位,高位丢弃,低位补0。

 

例如,9<<3可以转换为如下的运算:

<< 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0100 1000  (72 在内存中的存储)

所以9<<3的结果为 72。

 

又如,(-9)<<3可以转换为如下的运算:

<< 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

-----------------------------------------------------------------------------------

1111 1111 -- 1111 1111 -- 1111 1111 -- 1011 1000  (-72 在内存中的存储)

所以(-9)<<3的结果为 -72

 

如果数据较小,被丢弃的高位不包含 1,那么左移 n 位相当于乘以 2 的 n 次方

 

【实例】对上面的结果进行校验。

#include <stdio.h>

int main(){

    printf("%d, %d\n", 9<<3, (-9)<<3 );

    return 0;

}

 

运行结果:

72, -72

 

************右移运算(>>)

 

右移运算符>>用来把操作数的各个二进制位全部右移若干位,低位丢弃,高位补 0 或 1。如果数据的最高位是 0,那么就补 0;如果最高位是 1,那么就补 1。

 

例如,9>>3可以转换为如下的运算:

>> 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)

-----------------------------------------------------------------------------------

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001  (1 在内存中的存储)

所以9>>3的结果为 1。

 

又如,(-9)>>3可以转换为如下的运算:

>> 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

-----------------------------------------------------------------------------------

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 1110  (-2 在内存中的存储)

所以(-9)>>3的结果为 -2

 

如果被丢弃的低位不包含 1,那么右移 n 位相当于除以 2 的 n 次方(但被移除的位中经常会包含 1)。

 

【实例】对上面的结果进行校验。

#include <stdio.h>

int main(){

    printf("%d, %d\n", 9>>3, (-9)>>3 );

    return 0;

}

运行结果:

1, -2

 

=============原码、反码、补码:

 

一、什么是原码、反码和补码

  在计算机内部存储的带符号数都是以补码形式存储,用补码形式进行运算的。以整型数为例,且假定字长为8位。

  1、原码

  整数X的原码是指:其符号位为0表示正,为1表示负;其数值部分就是X的绝对值的二进制数。X的原码通常用【X】原表示。如:

  【+100】原=01100100 【+0】原=00000000

  【-100】原=11100100 【-0】原=10000000注意:在原码中,零有两种表示形式。

  原码表示法简单易懂,与真值(带符号数本身)转换方便,只要符号还原即可,但当两个正数相减或不同符号数相加时,必须比较两个数哪个绝对值大,才能决定谁减谁,才能确定结果是正还是负,所以原码不便于加减运算。

  2、反码

  X的反码是指:对于正数,反码与原码相同;对于负数,符号位不变,其数值位X的绝对值取反(1变0,0变1)。X的反码通常用【X】反来表示。如

  【+100】反=01100100 【+0】反=00000000

  【-100】反=10011011【-0】反=11111111

  注意:在反码中,零也有两种表示形式。

  反码运算也不方便,通常用来作为求补码的中间过渡。

  3、补码

  X的补码是指:对于正数,补码与原码相同;对于负数,符号位不变,其数值位X的绝对值取反后在最低位加1。X的补码通常用【X】补来表示,实际上,【X】补=【X】反+1。如:

  【+100】补=01100100 【+0】补=00000000

  【-100】补=10011100 【-0】补=00000000

  注意:在补码中,零有唯一的编码,【+0】补=【-0】补=00000000。

  补码运算简单方便,符号位可以作为数据的一位参与运算,不必单独处理;二进制的减法可用其补码的加法来实现,简化了硬件电路。

1.  负数原码和反码的相互转化负数原码转化为反码:符号位不变,数值位按位取反。如:原码 1100 0010
反码 1011 1101负数反码转化为原码:符号位不变,数值位按位取反。反码 1011 1101
原码 1100 00102.  负数原码和补码的相互转化负数原码转化为补码:符号位不变,数值位按位取反,末尾加一。原码 1100 0010
反码 1011 1101 //符号位不变,数值位按位取反
补码 1011 1110 //末尾加1负数补码转化为原码:符号位不变,数值位按位取反,末尾加1。补码 1011 11101100 0001 //符号位不变,数值位按位取反
原码 1100 0010 //末尾加13.负数反码和补码的相互转化负数反码转化为补码:末尾加1。反码 1011 1101
补码 1011 1110负数补码转化为反码:末尾减1(注意,此处的反码是指原码的反码)。补码         1011 1110
原码的反码   1011 1101
//减法 借位        

  补码转换为原码:符号位不变,数值位按位取反,末位再加1。即补码的补码等于原码.

一个汉子等于两个字节,包括中文标点符号;一个英文占一个字节;

两个16进制数等于一个字节;一个字节占8位,最多表示-128~127或者0~255;

很多计算,都使用0x这样的16进制进行运行:如 0xF的二进制为 1111 ,即四个1。0xFF的二进制为 1111 1111 ,即8个1的二进制形式每多一个F就是多一个4位的1111。最多8个F。

***16进制的反码和补码:

将一个十六进制整数按位取反并加 1,就生成了它的补码。一个简单的十六进制数字取反方法就是用 15 减去该数字。下面是一些十六进制数求补码的例子:

6A3D --> 95C2 + 1 --> 95C3
95C3 --> 6A3C + 1 --> 6A3D

通过检查十六进制数的最高有效(最高)位,就可以知道该数是正数还是负数。如果最高位 ≥ 8,该数是负数;如果最高位 ≤ 7,该数是正数。比如,十六进制数 8A20 是负数,而 7FD9 是正数.

 

这篇关于C语言之位运算/原码/反码/补码、进制间的转换、常规应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017758

相关文章

C语言中的浮点数存储详解

《C语言中的浮点数存储详解》:本文主要介绍C语言中的浮点数存储详解,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、首先明确一个概念2、接下来,讲解C语言中浮点型数存储的规则2.1、可以将上述公式分为两部分来看2.2、问:十进制小数0.5该如何存储?2.3 浮点

Java逻辑运算符之&&、|| 与&、 |的区别及应用

《Java逻辑运算符之&&、||与&、|的区别及应用》:本文主要介绍Java逻辑运算符之&&、||与&、|的区别及应用的相关资料,分别是&&、||与&、|,并探讨了它们在不同应用场景中... 目录前言一、基本概念与运算符介绍二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. &:非短

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

Python使用PIL库将PNG图片转换为ICO图标的示例代码

《Python使用PIL库将PNG图片转换为ICO图标的示例代码》在软件开发和网站设计中,ICO图标是一种常用的图像格式,特别适用于应用程序图标、网页收藏夹图标等场景,本文将介绍如何使用Python的... 目录引言准备工作代码解析实践操作结果展示结语引言在软件开发和网站设计中,ICO图标是一种常用的图像

Spring AI集成DeepSeek三步搞定Java智能应用的详细过程

《SpringAI集成DeepSeek三步搞定Java智能应用的详细过程》本文介绍了如何使用SpringAI集成DeepSeek,一个国内顶尖的多模态大模型,SpringAI提供了一套统一的接口,简... 目录DeepSeek 介绍Spring AI 是什么?Spring AI 的主要功能包括1、环境准备2

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav

基于Python实现多语言朗读与单词选择测验

《基于Python实现多语言朗读与单词选择测验》在数字化教育日益普及的今天,开发一款能够支持多语言朗读和单词选择测验的程序,对于语言学习者来说无疑是一个巨大的福音,下面我们就来用Python实现一个这... 目录一、项目概述二、环境准备三、实现朗读功能四、实现单词选择测验五、创建图形用户界面六、运行程序七、

Python3脚本实现Excel与TXT的智能转换

《Python3脚本实现Excel与TXT的智能转换》在数据处理的日常工作中,我们经常需要将Excel中的结构化数据转换为其他格式,本文将使用Python3实现Excel与TXT的智能转换,需要的可以... 目录场景应用:为什么需要这种转换技术解析:代码实现详解核心代码展示改进点说明实战演练:从Excel到

MobaXterm远程登录工具功能与应用小结

《MobaXterm远程登录工具功能与应用小结》MobaXterm是一款功能强大的远程终端软件,主要支持SSH登录,拥有多种远程协议,实现跨平台访问,它包括多会话管理、本地命令行执行、图形化界面集成和... 目录1. 远程终端软件概述1.1 远程终端软件的定义与用途1.2 远程终端软件的关键特性2. 支持的