数据存储解析和例题

一.原码,反码,补码
对于无符号数,原码反码补码相同
原码 反码 补码
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同
①原码
直接将二进制按照正负数的形式翻译成二进制就可以
②反码
//将原码的符号位不变,其他位依次按照取反就可以得到了
③补码
//在反码的基础上加1

int main()
{
	int a = 20;
	//00000000000000000000000000010100  --原码
	//00000000000000000000000000010100  --反码
	//00000000000000000000000000010100  --补码
	//转化为16进制位
	//0x00000014    在VS的编译器中他的存储方式是小端字节序
	int b = -10;
	//1000000000000000000000001010 -- 原码
	//1111111111111111111111110101 -- 反码
	//1111111111111111111111110110 --补码
	//0xFFFFFFF6 
}

在这里插入图片描述

对于整形来说:数据存放内存中其实存放的是补码
为什么呢?
1.在计算机系统中,数值一律用补码来表示和存储。原因在于使用补码,可以将符号位和数值域同时处理;同时,加发和减法也可以同时处理,并且在CPU中只有加法器
2.那你就会说1-1是不是就没法计算了呢?
转换为1+(-1)

二.大小端介绍
大端存储模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端存储模式:是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中;
对于VS编译器来说,是小端存储模式,且左边为低地址,右边为高地址 低----------------高
思考题:设计一个小程序来判断当前机器的字节序
解析:我们拿出一个整数的第一个字节,比如int a = 1 0x00000001
大端模式 00 00 00 01
小端模式 01 00 00 00
如果是00表示大端 , 是01表示小端
这里封装一个函数来判断当前机器的大小端

int check_sys()
{
	int a = 1;
	char* p = (char*)&a;
	//返回1表示小端
	//返回0表示大端
	return *p;
}
int main()
{
	int a = 1;
	char* p = (char*)&a; //char* 能表示我当前访问的自己大小
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

思考题2.
输出什么?

int main()
{
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	char a = -1;
	//11111111
	//应为打印的是%d所以这里要发生整形提升,对于char来说是有符号的
	//所以前面补符号位
	//11111111111111111111111111111111 -- 补码
	//原码就是-1
	signed char b = -1;
	//11111111
	//和char的性质一样
	unsigned char c = -1;
	//11111111  最前面的并不是符号位,所以发生整形提升的时候补充0
	//0000000000000000000110011111111
	//所以对应的十进制数就是255
	printf("a = %d,b = %d,c = %d", a, b, c);
	return 0;
}
//结果是 -1 -1 255

思考题3.
输出什么?


int main()
{
	char a = -128;
	//10000000000000000000000010000000 
	//11111111111111111111111101111111
	//11111111111111111111111110000000
	//发生截断
	//10000000
	//11111111111111111111111110000000--补码
	//但是对于一个无符号数来说,原反补是相同的
	//所以a = 4294967168转换为无符号十进制数  是一个很大的数字
	printf("%u\n", a);  //%u--打印十进制的无符号数
	return 0;
}

对与一个char的范围是
0-127 -1 — -128 这个可以表示为一个圆盘左边部分从上到下是-1 —> -128 右边从下到上是127 --> 0
整体的范围是-128 --> 127
在这里插入图片描述

int main()
{
	char a = -128;
	printf("%u\n", a);
	return 0;
}

//这里你要思考对于一个char类型能存储下一个128吗?
int main()
{
	char a = 128;  //127 + 1  根据上面的圆盘就知道其实也是打印出来-128的意思
	printf("%u\n", a);
	return 0;
}

按照补码的形式进行运算,最后格式化成为有符号整数

int main()
{
	int i = -20;
	unsigned int j = 10;
	//10000000 00000000 00000000 00010100
	//11111111 11111111 11111111 11101011
	//11111111 11111111 11111111 11101100 -- -20补码
	//00000000 00000000 00000000 00001010 -- 10的补码
    //11111111 11111111 11111111 11110110  --结果
	//11111111 11111111 11111111 11110101 -- 结果的补码
	//10000000 00000000 00000000 00001010  -- 结果原码  -10
	printf("%d\n", i + j);
}

结果是什么?

#include<windows.h>
int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
		Sleep(100);// 单位是ms  也就是0.1s 
	}
	return 0;
}
//你会发现对于一个unsigned int 类型的压根就不可能小于0,所以这是一个死循环

经典题

int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}
//结果 255   因为对于char 来说-128 --> 127 的范围,你好好想一下刚才的圆盘-128 -1 = -129  转换过来就是127
//知道他从右下转到右上遇见了字符'0' ,他就停止了

错误想法:char类型的a定义的数组中存放的是-1,-2 …-1000,但是strlen遇不见\0 所以strlen的大小是一个随机值

unsigned char类型题目

unsigned char i = 0;
int main()
{
	for (i = 0; i <= 255; i++)
	{
		printf("hello world\n");
	}
	return 0;
}

结果也会是死循环 因为unsigned char 的大小最大也只是255,所以一直再循环体内部满足条件,就一直打印"hello world"

三.浮点型在内存中的存储

int main()
{
	int n = 9;
	float* pFloat = (float*)&n;// float* 访问的也是4个字节的空间大小
	printf("n的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);

	*pFloat = 9.0;
	printf("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

在这里插入图片描述
解析:pFloat 这个指针来说,它认为int = 9 在内存中存储的补码应该是浮点类型的
00000000 00000000 00000000 00001001
0 00000000 00000000000000000001001
还原回来:(-1)^ 0* 0.00000000000000000001001 * 2^-126
无限接近0,所以打印出来是0.000000

*pFloat = 9.0的存储形式是
(-1)^ 0 * 1.001 * 2^3 然后再把它存到内存中 M=3加127 转化为二进制
0 10000010 00100000000000000000000 – 计算值认为这个就是补码,且符号位表示正。
注意事项:
在这里插入图片描述
32位的情况:
在这里插入图片描述

int main()
{
	float f = 5.5;
	//5.5
	//101.1
	//(-1)^0 * 1.011 * 2^2
	//S=0
	//M = 1.011
	//E =2
	//E在内存中真正的存储方式是要加127的  把129转化为二进制数
	// 0 10000001 011 00000000000000000000(补齐23位M)一共32位,这才是真正的在内存中存储的二进制序列
	//0x 40 b0 00 00 以16进制的形式展现内存
}

64位情况
在这里插入图片描述
指数E从内存中拿出来的情况:
1.对于E不为全0或不为全1的情况下:对于32位需要-127,对于64位需要-1023才能得到它真正的E值
2.E为全0情况:对于这种情况你要想他已经加了127结果还全为0,说明原来是-127,这是一个非常小的数
0 00000000 01100000000000000000000
0.011 * 2^-126
对于E为全0的情况我们规定在还原的时候M不需要在补1,E也直接改为固定值1-127
3.E为全1的情况:E+127 = 255,所以原来E=128
1.xxx * 2^128 这个数太大了,计算不了,所以也不考虑了。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值