目录

【飞郁2022新课程】14 - 有符号和无符号区别

一、原码 反码 补码

从不同的角度去看情况,往往会得到不同的结果,在前面的课程我们举得例子都是正数,没有看到负数,难道计算机没有负数一说?当然不是,在讲有符号 和 无符号的时候 我们需要了解一下计算机是怎么存储数据.

1.1 原码 补码 反码

计算的二进制数据有3种表现形式分别为:原码 补码 反码.

首先我们看到原码是可以理解的,例如:以1个字节计算,10的原码是:0000 1010

那为什么会有补码和反码的存在呢?这是由于CPU的关系,等会我们再细致讲解.

我们的计算机在内存中其实存放二进制数据的形式是补码.

之前的课程中我们讲到的例子全是正数没有用到过负数.

其实计算机的类型会分为有符号类型(正/负号)和无符号类型(正号没有负号),一般我们的正号是可以省略的.

它们均可以在类型名前加"unsigned"关键字表示为无符号,默认不加这个关键字就是有符号类型,

1.2 符号位和数值位

原码 补码 反码三种形式均有符号位和数值位两部分,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/a4dfdfe1f90d325740f70d9a74ffdccfc2e5629e.png@338w_225h_progressive.png

1.2.1 符号位:

符号位 0 表示正数,符号位 1 表示负数.

1.2.2 数值位:

三种表示形式各不相同,这样也是有原因的,因为使用补码,可以将符号位和数值域统一处理.

加法和减法也可以统一处理(因为CPU只有加法器,而没有减法器).

补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

1.2.3 原码怎么计算得到补码呢?

原码的绝对值

1.直接将二进制按照正负数的形式得到原码后取绝对值后翻译成二进制就可以了.

反码

2.位依次按位取反就可以得到了.

补码

3.反码 +1 就得到补码.

注意:正数的原码、反码、补码相同.

1.2.4 例如:

unsigned char a = 198; char b = -58; printf("%d\r\n",b);//内存中存198 return 1;

最高位1表示负数,数值位表示值

1.原码取绝对值:1011 1010 (原码) => -58 => -011 1010 =>|58| => |-011 1010| => 0011 1010

2.按位取反:0011 1010 => 1100 0101

3.反码+1遵循逢二进一:1100 0110 +1 => 0xC6

这就得到了我们变量b在内存中存的补码值为0xC6.

所以这就解释了为什么我们看变量a,b的内存值都是0xC6.

1.2.5 有符号无符号总结:

1.符号位 0 表示正数,符号位 1 表示负数.

2.正数的原码就等于补码.

3.负数的原码不等于补码.

4.补码等于原码取绝对值转换成二进制然后取反再加1得到的.

5.所以仅仅从内存看值 是无法确定是有符号还是无符号的,计算机是识别不了的,需要编译器操作一系列指令来识别.

1.2.6 为什么用补码储存呢?

有的人会问用原码多好还能直接看出来

其实并不然,计算机有时候还并不是那么智能的

CPU只会加法并不会减法所以才是补码存储也就是说CPU只有加法器并没有减法器

我们来看看正数的补码 和 负数的补码 相加是不是得到了正确的结果呢?

1.2.7.例如:

10+(-2)=8? 看看计算机的计算流程

正数10的补码等于原码:

0000 1010

负数-2的补码不等于原码:

这里要计算出补码

1000 0010 取绝对值

0000 0010 取反

1111 1101 +1得到补码

1111 1110 计算机验证下就是等于-2

由于CPU只有加法器

我们就把2个补码相加

0000 1010

1111 1110

逢二进一等于

0000 1000

验证下是不是等于8?

计算是对的

所以明白了吗??

二、有符号 无符号

1.经过上面的讲解 我们在来理解一下 有符号 和 无符号

2.观察下面代码 并编译 显示

3.我们观察内存中 这2个变量的值

4.发现一样 !!再回忆下上面我们讲到的负数的补码 是不是就迎刃而解了

5.顿时恍然大悟的感觉

#include <stdio.h> void main() { unsigned char a =198 ; char b = -58; printf(“a: %d\n”,a); printf(“a: %d\n”,b); system(“pause”); }

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/3c6a1a7c6b10b7865ed2083bf61d969c1d4f070e.png@587w_147h_progressive-20211124211222496.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/6ffe4a577adee57b495566074c5e72364bdee49c.png@588w_149h_progressive.png

我们这里面发现 a和b 的输出是不同的

我们到内存中看看情况

发现a和b 在内存中是相同的,都是C6

是否有符号不会影响他在内存中的存放方式呢?相信经过上面的讲解大家也知道怎么回事了.

因为内存中只有0和1 表示不了正负的 都是人为规定的

无符号范围 0 —- 255

有符号范围 0 —-127 和 -128—- -1

为什么这样 ? 人为规定的!

经过上面讲解原码 反码 补码的时候知道了为什么都是C6的原因.

这里我们还需要知道无符号的198是怎么转为有符号-58的.

其实很简单,我们只需要, -128 +(198-128) = -58 .

这里给大家画了一张图 以便大家去理解这个公式的由来:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/7ebf187633f18dcc5e9a5c49d489a28bdf5df0a6.png@798w_810h_progressive.png