signed、unsigned与整形在内存的存储
无符号整数vs有符号整数
有无符号的概念一般是用来描述整形的
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
原反补
一个变量的创建是要在内存中开辟空间的,变量的类型决定了开辟空间的大小。
那么,数据在所开辟的内存中到底是如何存储的呢?
-
有符号数
int a = 10;
int b = -20;
我们知道,编译器为a分配四个字节的空间。那如何存储呢?首先,任何数据在内存中都是以二进制的形成存储的。
那么对于有符号数,一定要能够表示该数是正数还是负数,那么就诞生了符号位,随之就是数据位。
对于一个有符号数来说,它的二进制在内存中分为符号位和数据位,符号位是最高的那一位,剩下的全是数据位。
计算机中的有符号数有三种表示方法,即原码、反码和补码
三种表示方法均有符号位和数值位两部分,符号位都是用0表示”正“,用1表示”负“,而数值位三种表示方法各不相同。
对于正数来说,三种表示方法原码、反码、补码是完全相同的
而对于负数来说,三种表示方法是完全不同的。
负数的三码转换规则
- 先把数据转换成二进制形式,位数根据数据类型而定,这就是原码
- 符号位不变,其它位按位取反,这就是反码
- 在反码的基础上+1,就得到补码
整形真正存储在内存中的是补码
//demo int a = 10;//四字节,32个比特位,是个正数,最高位是0代表正数,其余全为数据位, 00000000000000000000000000001010//原码==反码==补码 int b = -20;//四字节,32个比特位,是个负数,最高位是1代表负数,其余全为数据位 10000000000000000000000000010100//原码 11111111111111111111111111101011//反码 11111111111111111111111111111100//补码
-
无符号数:不需要转化,也不需要符号位,原反补相同
那么,存放时是原码转到补码,那取出时呢?有两种方法
**方法一:**按照原码转到补码的方法逆着来一遍就ok了
**方法二:**继续安装原码转到补码的方法正着来一遍也可以
值得一提的是,方法一更容易理解,毕竟怎么取就怎么放,方法倒着来一遍就ok,很通俗易懂
但是真正在计算机中运行的方法是方法二,因为这样可以节省硬件电路。
深入理解变量内容的存入和取出
可以看到,其实存入到内存中的补码,实际上跟变量的类型是无关的。这是因为,不管创建什么类型的变量,只需要开辟好空间就可以了,这块空间用来存放数据的补码,仅此而已。而影响存放数据补码的因素是数据本身的正负,跟变量的类型无关。
那么变量的类型什么时候起到作用呢?在使用变量的时候起到作用!
结论:
存:字面数据必须先转成补码,再放入空间当中。所以,所谓符号位,完全看数据本身是正数还是负数。和变量是否有符号无关!
取:取数据一定要先看变量本身类型,然后才决定要不要看最高符号位。如果不需要,直接二进制转成十进制。如果需要,则需要转成原码,然后才能识别。
十进制二进制快速转化
口诀:1后面跟n个0,就是2的n次方
一般来说需要口算的,那都是数字较小的,数字较大的一般都用计算器。
把数字分成几个2的n次方,然后每一个数,有几个n,1后面就有几个0
大小端
由于CPU内的通用寄存器大于1个字节,访问数据时,就必然存在顺序的问题。大小端的差异是由于硬件而存在的,所以在相同的机器上,用的是同一种模式。
大端:
高权重放入低地址,低权重放入高地址
小端:
低权重放入低地址,高权重放入高地址
所以三个字就可以总结出规律:小低低
为什么在计算机中存储的都是补码
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)。另外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
整形取值范围
为了简单,以char举例
char能容纳8个字节,取值范围很显然是从全0到全1,即[00000000,11111111]
对于有符号的char,最高位是符号位,那么数值位就有七位
正数从0到127即[00000000,01111111]
负数从0到-127即[10000000,11111111]
而0重复了两次,但是很显然00000000
比10000000
更适合充当0的角色
于是就剩下了一个10000000
,而计算机是不会放过任何一个数值的,任何一个数值都能造成很大的影响,
而上面已经确定了范围[-127,127],中间没有数字可以用10000000
来表示,而又因为是char的取值范围(连续数据),
所以就只能作为-128或者128,但是很显然它更适合充当-128的角色。因为最高位是1
所以就确定了有符号char的范围为[-128,127]
而对于无符号char的范围就是全0到全1,即[00000000,11111111],即[0,256]
所以就总结出规律:
整形的取值范围:
无符号: [ 0 , 2 n − 1 ] [0,2^{n} - 1] [0,2n−1]
有符号: [ − 2 n − 1 , 2 n − 1 − 1 ] [-2^{n-1},2^{n-1}-1] [−2n−1,2n−1−1]