目录
不要直接对int 类型变量强转为char类型,不管是大端还是小端,转完后都可以保留一部分地位(int里面放的值不超过8位二进制数表示的的整数,就能被完全保留下来)
整数在内存中的存储
整数在内存中存的是二进制补码,正数的 原、反、补码相同,负数的补码,由源码取反加一获得。
对于有符号整数,把最高位看作符号位。无符号整数,没有符号位,全表示正数
对于整形,二进制里面存放的是二进制补码。
内存的大小端
什么是大小端
超过一个字节的数据在内存中就存在着顺序问题,一般分为大端和小端。
讨论的是字节的顺序。
大端字节序:低地址存高二进制数,高地址存低二进制数。
小端字节序:低地址存低二进制数,高地址存高二进制数。
在调试窗口中,为了方便观察,显示的是十六进制数,但本质依然是一个32位(int类型)的二进制数。
我自己的小疑惑解析:问题是为什么0x11223344就刚好放满呢?
答:二进制转16进制就是,每4位表示一个十六进制数,32位能表示8个,也就是说这个11223344,每一位都是一个十六进制数,每一位都需要4个二进制来放。所以能放满
而且顺序是倒过来的,这个图片就是n里面存放的二进制数。他存是这么存,转成十进制还是得从低址往高地址相加。只是把二进制数倒着放而已
0x11223344的二进制数本质还是,只不过倒着放在了VS的内存中。
纠正
大端和小端的本质是字节序,一个字节八位,每八位的倒着存放的
不完全是倒着存的,只有每个字节序是倒着放的,里面的二进制位可没有倒着
列如,0x12345678
他的二进制位应该是,
那有什么用呢?
如果你想从监视窗口那直接由十六进制转十进制或者二进制,那么就得注意了
以0x12345678在内存中举例
转十进制应该是 :
7*16(一次)+8*16(0次)+5*16(3次)+6*16(2次)+3*16(5次)+4*16(4)+1*16 (7次)+2*16(6)
次方序
0 1 3 2 5 4 7 6
不要直接对int 类型变量强转为char类型,不管是大端还是小端,转完后都可以保留一部分地位(int里面放的值不超过8位二进制数表示的的整数,就能被完全保留下来)
有符号 char 和 无符号 char
signed char ,规定:内存中最高位为符号位,有效数值位只有7位,
也就是说 signed char 最大也就127,最小-128(7位二进制数最大能表示 2的7次方减一,127),把最高位看成正负号的话。
我以为最小-127呢,结果有规定,1 0 0 0 0 0 0 0,为-128,按道理-128一个char 是存不下的
他需要9位表示,-128补码按道理应为1 1 0 0 0 0 0 0 0,没办法这就么规定
而 unsigned char 8 位二进制全表示正数,最大为2的8次方减一,255
char 的二进制补码突破
也就是说,当127的补码再加一,0 1 1 1 1 1 1 1,变成1 0 0 0 0 0 0 0就会变成-128,再加一就是1 0 0 0 0 0 0 1 -127,突破正127后变成-128 ,补码再增加的话,这个负数也在增加,最终来到,1 1 1 1 1 1 1 1,也就是-1的补码。
无符号的话突破就突破了,上限是255,1 1 1 1 1 1 1 1二进制补码。 再突破就是0了,因为放不下。
一个-1是如何存入 char 类型的。
首先,-1是一个整型,所以他的二进制为有32个,如图第一行,又因为一个数在二进制中存的是补码,所以转成补码是如图第三行,然后可以存了,又因存入的是一个char 类型,所以32位根本放不下,只取右边的8八位
%d 打印无符号char 类型里面的-1
首先-1存在一个char内存中的补码是1 1 1 1 1 1 1 1,%d意思是以有符号整形的形式打印,所以补码1 1 1 1 1 1 1 1,先整形提升,根据原类型提升(如果是无符号数最高位补0,有符号数补符号位),如图第二行,然后%d再来判断,%d把这个补码看成有符号数,最高位是0,代表是个正数,此时就不需要转原码了,直接把这个二进位数当成整数打印出来。
第一个圈为,计算-128的补码然后截断给到 char a
第二圈为整形提升,提升完,由无符号整形打印,把整形提升完后的补码看作无符号整数
char周期图(有符号)
有符号char周期图
浮点数在内存中的存储
范围头文件为:float.h ,整数范围文件在 limits.h
最大数计算
short类型最大数计算 ,short占2个字节,16个二进制位,最高位看成符号位舍去,有效位15位,在,最大数就等于2的15次方减一。 (其实你带进去的时候发现根本没有2的15次,最高是14,这里值得注意的是,从2的0次一直加到2的14次就等于2的15次方减一,就是最大数)
计算公式
用计算器算时,小数点后一位,就是1除2(2的一次),第二位就是1除4(2的二次),第三位就是1除8(2的三次),以此类推。
举例,float a = 6.6(我也是随便写,正边写边算呢),二进制位等于(无法精确写出)
1、 0.1 这个1=2的负一次方,等于二分之一,也就是0.5 ,
2、 0.11 等于 0.5 + 0.25(1除4) = 0.75 太大了所以舍去(第二个1就是2的负二次方)
3、 0.101 等于 0.5 + 0.125(1除8) =0.625也太大
4、 0.1001 等于 0.5+(1除16)2的负四次方,也就是十六分之一,等于0.0625, 0.5+0.0625=0.5625,太小继续往后添一个二进制1
5、 0.10011等于 这里用分数逼近把感觉好算一点,0.6等于五分之三,二分之一+十六分之一+32分之一等于 32分之16+32分之2+32分之1=32分之19(感觉也不是很好算)还是靠计算器吧。0.5625+0.03125(1除32)=0.59375(很接近了)小了就在后面加一,大了就把你计算的这一位变0,在再后面添1看看是大还是小,大了变0看下一位。0.100111 = 6、 0.10011 + 0.000001(1除64)= 0.59375 + 0.015625 =0.609375,大了归0,再看后面的1
7、 0.1001101 = 0.59375 + (1除128) 0.0078125 = 0.6015625
8、 0.10011001 = 0.59375 + (1除256)0.00390625 = 0.59765625
9、 0.100110011 = 0.59765625 + (1除512)0.00195312 = 0.59960938(2的负9次方了),最后那俩位38是375约等的手机没横过俩约等了,1除256那儿是对的
10、 0.1001100111 = 0.599609375 + (1除1024)0.0009765625 = 0.6005859375.
11、 0.10011001101 = 0.599609375 + (1除2048)0.00048828125 =0.600097656625
12、 0.100110011001 = 0.599609375+(1除4096)0.00048828125 = 0.599853515625
13、 0.1001100110011 = 0.599853515625 +(1除8192)0.0001220703125 = 0.5999755859375
14、 0.10011001100111 = 0.5999755859375 +(1除16384)0.00006103515625 =0.60003662109375‘
这后面貌似规律一样了,等会儿可以猜着写一下具体的存储。float的有效位是23位
110.100110011001100110011001101100(6.6的二进位猜写)下面会用
由此证明一个浮点数有可能无法再内存中精确保存。二的负14次方了已经
浮点数的具体存储
规则表:
double 类型的区别,就在于是64个二进制位,S 占1个,E占11个,剩下52给有效数字M,所以他的精度更高。还有就是存E的时候加上1023
浮点数的存入
拿上面的6.6的二进制位举例。110.100110011001100110011001101100
首先,先转成一个小于2大于1的科学计数法的数,1.10100110011001100110011乘2的2次方
就能还原,这个2的2次方也是有用的。’
然后咱们就来分析,谁是S 谁是 E 谁是 M,我们只需存这仨就行。
S,第一位,只需要看存的这个数是正数还是负数就行,正数就是0,负数就是1
所以上面低二张图的第一个S就是 0
0
然后看E,这个E就是上面变成科学计数法法表示的二进制数乘的那个2的2次方,的指数2,存的时候有小细节,float类型给E的空间只有8位,其次这8位全当作无符号数识别(因为会有负数),规定:得到的指数必须要加127再存进去。所以E=129=10000001(图4)
E要点:也就是是说0~126,表示负数,127~255表示正数(指数),其实不难发现咱们一个14次已经非常非常精确了。
0 10000001 (目前咱已经存了这些了)
M,这儿也有细节,存的时候只存小数部分的二进制位(精度更高),也就是咱们只要
10100110011001100110011 这一坨
0 10000001 10100110011001100110011 (ok大致就是我的猜想数,我也不确定他们是不是有规律的)咱们直接给他转成16进制然后去内存里面看一下。
0100 0000 1101 0011 0011 0011 0011 0011
4 0 D 3 3 3 3 3
由此可以看见咱们还没走错,(倒着存的)放归倒着放不影响咱们的计算,和机器的识别。
浮点数的取出
一般来说,只需要把那两个小细节还回去就行了,
0 10000001 10100110011001100110011,那它举例,
10000001=129,减去127,等于=2=E=指数,
10100110011001100110011,这一坨是小数,只要再前面加一个 1. 就行了
1.10100110011001100110011 ,小数点再向右边移动两位,因为指数是正2如果算出来最后是负2就向左移动,110.100110011001100110011,再转十进制就行,不过这是近似值我就不算了。
有两个特殊点就是
E等于0(00000000)二进制位,规定真实指数为-126。不用纠结记就完了。
如果拿 1.10100110011001100110011,这个举例,在移动小数点的时候,还得向左移动126位,这得多小。
还原的时候还不用添1了。
和E等于255(11111111) 二进制位,指数为127,向右移动127位,非常大,然后看符号位,表示正负无穷大