数据的存储
数据类型详细介绍 原码反码补码 大小端字节介绍和判断 浮点型在内存中的存储解析
数据类型
1.c语言类型分类
整形
char
unsigned char
signed char
short
unsigned short[int]//[]可以省略
signed short[int]
int
unsigned int
signed int
long
unsigned long[int]
signed long[int]
浮点数
float
double
构造类型
数组类型 int arr[10]
结构体类型 struct
枚举
联合
指针类型
int* p
char* p
void* pv
空类型
void(无返回无类型)
整数在内存中的存储
原码(打印) 反码 补码(存储在内存)
计算机中的有符号数(整形)有三个表达方式原码反码补码
符号位 0 正 1 负 在最高位
数值位
正数 原码反码补码 相同
int a = 20;//4个字节 32bit
//00000000000000000000000000010100-原码
//00000000000000000000000000010100-反码
//0000 0000 0000 0000 0000 0000 0001 0100-补码
//0x00000014(地址十六进制)
int b = -10;
//10000000000000000000000000001010-原码
//11111111111111111111111111110101-反码
//1111 1111 1111 1111 1111 1111 1111 0110-补码
//0xFFFFFFF6
因为计算机cpu只有加法器,原码补码计算相互转换,不需要额外的硬件电路
1 - 1
// 1 的原码反码补码都相同
//00000000000000000000000000000001
//-1
//10000000000000000000000000000001=原码
//11111111111111111111111111111110
//11111111111111111111111111111111-补码
// 1-1
//00000000000000000000000000000001
//11111111111111111111111111111111
//相加
//100000000000000000000000000000000多了一位左移 所以成00000000000000000000000000000000=0
大小端存储
大端(大端字节序):数据的低位存放在内存的高地址,数据的高位存放在内存的低地址
小端(小端字节序):数据的低位存放在内存的低地址,数据的高位存放在内存的高地址(普遍)
小端存储模式
//千 百 十 (高到低)
//0x00000014
//内存地址 (低到高)
//c8 c9 ca cb
//14 00 00 00
printf("%u")打印无符号数字
有符号的char(signed char)范围 - 128--127(char[]长度为255)
//内存(补码)
//00000000->0
//00000001->1
//00000010->2
//......
//01111111->127
//10000000->-128 : [1 10000000->1 01111111->1 10000000 ->-128
//......
//11111110->-2:[11111101->10000010->-2]
//11111111->-1:[11111110->10000001->-1]
无符号的char(unsigned char)范围0--255(100000000本来有符号位应该是 - 128,因为无符号就直接计算二进制)
//内存(补码)
//00000000->0
//00000001->1
//00000010->2
//......
//01111111->127
//10000000->128
//......
//11111110
//11111111->255
(char a = -128) == (char a = 128)->128 = 127 + 1相当于内存127位置 + 1成了 - 128的位置
unsigned int i = 0;
i-1 (原本应该是等于-1,但是因为无符号数,-1的补码11111....1111成为正数,因为正数原码反码补码都相同,所以就会成为非常大的数字)
-128-1=127,把-128--127这些数字组成一个圆,这就是一个闭环,也就可以解释的通,为什么127+1=-128 ;unsigned char里面 255+1=0
unsigned char i = 0;
for(i=0;i<=255;i++)//就会造成死循环,因为255+1=0,永远成立
//如何查看存储大小->VS->VC->include->limits.h
浮点数在内存中的存储
float
double
long double
根据国际标准IEEE(电气和电子工程协会)754,任何一个二进制浮点数V可以表示成下面的形式
(-1)^S*M*2^E
(-1)^S表示符号位,当S=0,V为正数;当S=-1.V为负数
M表示有效数字,大于等于1,小于2
2^E表示指数位
//9.0
//1001.0
// (-1)^S * M * 2^E
// (-1)^0 * 1.001 * 2^3
// s=0 m=1.001 e=3
//0.5
//二进制是 0.1 (因为小数点前面的0的权重是2^0,所以右边的5权重是2^-1,换算就是1/2=0.5
// 0.1=1.0 * 10^-1
//(-1)^0 * 1.0 * 2^-1
对于32个字节的浮点数,最高位的1位是符号位s,接着8位是指数e,剩下23位是有效数字m(单精度浮点数存储模型)
对于64个字节的浮点数,最高位的1位是符号位s,接着11位是指数e,剩下52位是有效数字m(单精度浮点数存储模型)
m因为大于等于1小于2,所以根据规定舍去前面的1,只存取小数点后面
根据规定E是无符号数,但是科学计数法可以出现负数,所以规定中间值,32位是127,64位是1023,存放e时必须加上中间数
比如2^10的E是10,存放32位浮点数时必须保存成10+127=137,即10001001
//5.5
//101.1
//(-1)^0 * 1.011 * 2^2
//s=0 m=1.011 e=2
// 0 (2+127=129) 10000001 01100000000000000000000
//01000000101100000000000000000000(二进制)->放到内存是十六进制
//0100 0000 1011 0000 0000 0000 0000 0000
//4 0 b 0 0 0 0
//0x40b0000
1.当e里面不全为0或不全为1
真实值e-127(32位)或e-1023(64位),然后m+1,把舍去的1加回来
2.当e全为0
规定e=1-127(32位)e=1-1023(64位),m不加1,这是一个无限接近0的数字
直接还原 ( .m ),前面不补1
//0 00000000 00000000000000000001001
//(-1)^0 * 0.00000000000000000001001 * 2 ^-126
3.当e全为1
表示这个数字无穷大