深度解析数据在内存中的存储

  • 常见的数据类型介绍
//整形家族
char       //字符数据类型
short      //短整形
int        //整形
long       //长整形
long long   //更长的整形
//浮点数家族
float       //单精度浮点数
double      //双精度浮点型
//它们的大小决定了使用范围,根据不同的类型开辟相应的内存空间。
//构造类型:
1.数组类型
2.结构体类型  struct
3.枚举类型   enum
4.联合类型   union
  • 整形在内存中的存储
    对于整形:数据在内存中存放的是补码,下面来了解原码、反码、补码
    计算机中的符号数有三种表示方法:原码、反码、补码。它们都是由符号位和数值位两部分组成。符号位用0表示“正”,用1表示“负”,数值位三种方法各不相同。
    原码:直接将二进制按照正负数的形式翻译成二进制。
    反码:将原码的符号位不变,其他位依次按位取反。
    补码:反码+1得到补码。正数的原、反、补码都相同。
    数据在内存中存放的是补码的原因在于:在计算机系统中,数值一律用补码来表示和存储,使用补码,可以将符号位和数据域统一处理,同时,加法和减法也可以统一处理(CPU只有加法器),此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
    整数:原、反、补码相同。
    负数:反码为除符号位外其他的位按位取反,补码为在原码的基础上+1。
  • 几个常见题型
#include<stdio.h>
int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d", a, b, c);//-1,-1,255
	return 0;
}

a b的输出比较好理解,但c可以来算一下
10000001 -1的原码
11111110 -1的反码
11111111 -1的补码
当一个无符号1字节的整形以%d 输出时就涉及到整形提升(表达式中的字符和短整形操作数在使用之前被转换为普通整形 32bit位),所有-1输出是在它前面加上符号位,有符号就加1,无符号就加0,直到补齐到32bit位,即变成 0000 0000 0000 0000 0000 0000 11111111,依据整形来说就是2^8-1=255
2.

#include <stdio.h>
int main()
{
	char a = -128;
	printf("%u\n", a);//4294967168  1111 1111 1111 1111 1111 1111 1000 0000
	return 0;
}

分析:char类型1个字节8个比特位,若表示无符号数字是00000000~11111111 即0~255 ,若表示有符号数最高比特位应是符号位。
此题中10000000 -128 整形提升后为:
1111 1111 1111 1111 1111 1111 1000 0000
按无符号整形十进制输出即4294967168
3.

#include <stdio.h> 
int main()
{
	char a = 128;
	printf("%u\n", a);//4294967168
	return 0;
}

char能表示的有符号数字的范围是0127和-1281,本题char中的8个比特位已经不够表示128,我们可以借一位表示,即110000000,此时最高位依然表示符号位,整形提升增加符号位后为
1111 1111 1111 1111 1111 1111 1000 0000
按无符号整形十进制输出即4294967168
4.

#include<stdio.h>
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n",i + j);//-10
	return 0;
}

i的二进制原码为1000 0000 0000 0000 0000 0000 0001 0100
j的二进制原补码为0000 0000 0000 0000 0000 0000 0000 1010
按照补码的形式进行运算,最后格式化成为有符号整数为
1000 0000 0000 0000 0000 0000 0000 1010 -10
5.

#include<stdio.h>
int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}
	return 0;
}

死循环了,因为i是一个无符号数不可能是负数,所以条件一定成立的,就一直死循环
6.

#include<stdio.h>
int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));//255
	return 0;
}

a是一个无符号的数组,无符号只能放入的数字范围为0-255,所以在第一个数字-1(11111111)存入数组时数组以一个无符号数255存入,-2以无符号数254存入,以此类推,当存入’0’时strlen就找到了停止符停下,此时数组里存入了255~1,有255个数字。
7.

#include<stdio.h>
int main()
{
	short num = 32767;
	short int a = num + 1;
	printf("%d\n", a);//-32768
	return 0;
}

短整形的取值范围是-32768~32767,16比特位,32767二进制为
0111 1111 1111 1111加1为
1000 0000 0000 0000此时为补码,-1然后按位取反任然是1000 0000 0000 0000
即-32768
8.

#include <stdio.h>
unsigned char i = 0;
int main()
{
	for (i = 0; i <= 255; i++)
	{
		printf("hello wolrd\n");
	}
	return 0;
}

死循环了,i是一个无符号数,范围是0~255,所以for循环的条件一直成立,程序一直循环下去。

  • 浮点型在内存中的存储

根据国际标准IEEE(电气电子工程师学会)754,任意一个二进制浮点数X可以表示成下面的形式:

  • (-1)S*M*2E

  • (-2)^S表示符号位,当S=0,X为正数;当S=1,X为负数

  • M表示有效数字,大于等于1,小于2

  • 2^E表示指数位
    IEEE 754规定: 对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
    在这里插入图片描述
    对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
    在这里插入图片描述
    IEEE 754对有效数字M和指数E,还有一些特别规定。 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
    IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部 分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效 数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
    至于指数E,情况就比较复杂。 首先,E为一个无符号整数(unsigned int) 这意味着,如果E为8位,它的取值范围为0~255;如果E为11位, 它 的取值范围为0~2047。但是,我们知道,科学计数法 中的E是可以出现负数的,所以IEEE 754规定,存入内存 时E 的真实值必须再加上一个中间数,对于8位的E, 这个中间数是127;对于11位的E,这个中间数是1023。 比如, 2^10的E是10,所以保存成32位浮点数时,必须 保存成10+127=137,即10001001。
    然后,指数E还可以再分成三种情况

  • E不全为0或不全为1
    这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M 前加上第一位的1。 比如: 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1 位,则为1.0*2^(-1),其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位 00000000000000000000000,则其二进制表示形式为:0 01111110 00000000000000000000000

  • E全为0
    这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为 0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字.

  • E全为1
    这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值