数据的存储

目录

C语言类型与数据的存储

字节序

整型提升与截断

整型提升的概念

整型提升的规则

截断的概念

示例讲解

整型的“循环”

浮点型在内存中的存储


C语言类型与数据的存储

C语言类型:
内置类型:char,short,int等等
自定义类型(构造类型)
类型的意义:决定了开辟内存空间的大小(大小决定了使用范围), 决定了看待内存空间的视角(相同的数字,整形和浮点型通过内存模块看到的结果是不一样的)

整型家族:char,short,int,long为什么char也算作整型?因为字符在电脑在电脑中存储为ASCII码值,整数 
浮点型家族:float,double
构造类型:数组类型,结构体类型,枚举类型,联合类型
 指针类型
 空类型:void

数据的存储:
 大端(存储)模式:是指数据的低位(如个位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中
 小端(存储)模式:是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中

字节序

如何验证本机的字节序?我们已经知道了大端和小端的存储模式,所以我们可以将一个整型变量存进去,因为字符变量是只能存储一个字节的,所以我们再用字符变量就可以查看低地址的字节是什么,由此来判断字节序

int 字节序()
{
	int a = 1;
	return *(char*)&a;   
	      // ↑强制转换成字符指针类型
	//大端:00 00 00 01
	//小端:01 00 00 00 
}
int main()
{
	int ret = 字节序();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

整型提升与截断

整型提升的概念

整型提升是C语言中的规定,即在进行表达式的计算时,数据类型需要先转化为int型才能够进行

整型提升的规则

分为两种,一种为无符号整型,一种为有符号整型,其中无符号整型在进行整型提升的时候前面自动补0,有符号整型在进行整型提升的时候前面自动补最高位

截断的概念

当数据的大小超过该类型所能存储的大小时,就会发生截断,只存储能够保存的一部分

示例讲解

int main()
{
	unsigned char a = 200;
	//11001000
	unsigned char b = 100;
	//01100100
	unsigned char c = 0;
	//a和b整形提升(有符号数按照最高位补,无符号数直接补0)
	//000000000000000011001000
	//000000000000000001100100
	//000000000000000100101100
	//相加和存到c中,但是c只能存8位,发生截断,所以存的是00101100
	c = a + b;
	//以%d形式打印,c前再次补0,但是a+b的计算结果是按照有符号数得到的,所以以%d输出不会变
	printf("%d %d\n", a + b, c);
	return 0;
}
运行结果:
300 44

int main()
{
	char a = -1;
	//10000000000000000000000000000001原码
	//11111111111111111111111111111111补码
	//11111111字符类型8个比特位
	signed int b = -1;
	//11111111111111111111111111111111
	unsigned int c = -1;
	//11111111111111111111111111111111
	signed char d = -1;
	//11111111
	unsigned char e = -1;
	//11111111
	printf("%d %d %d %d %d\n", a, b, c, d, e);
	//为什么c打印出来不是4294967295?因为使用的是%d而不是%u
	//为什么e打印出来是255?涉及到了整形提升与截断,整形提升之后是补码,注意换为原码进行打印
	return 0;
}
运行结果:
-1 -1 -1 -1 255
int main()
{
	char a = -128;
	//1000 0000 0000 0000 0000 0000 1000 0000
	//                              1000 0000
	//1111 1111 1111 1111 1111 1111 1000 0000
	//%u打印,原反补相同
	printf("%u\n", a);
	return 0;
}
运行结果:
4294967168

整型的“循环”

int main()
{
	char a[1000];
	int i = 0;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d\n", strlen(a));
	//因为数组为字符数组,又因为里面的数据为有符号整型,所以可取的数值范围是-128-127,有符号整型的数字变化为0,1...127,-128,-127...-1,所以从数组a中的数据从-1到-128之后为127,最后到0,再是-128.但是strlen遇到0就结束,所以结果为255
	return 0;
}
int main()
{
	unsigned char a = 0;
	for (a = 0; a <= 255; a++)
	{
		printf("hello world\n");
	}//死循环,因为a变为255后就又变成0了
	return 0;
}

浮点型在内存中的存储

int main()
{
	int n = 9;
	float* p = (float*)&n;
	printf("n的值为%d\n", n);
	printf("*p的值为%f\n", *p);
	*p = 9.0;
	printf("n的值为%d\n", n);
	printf("*p的值为%f\n", *p);
	return 0;
}
运行结果:
n的值为9
*p的值为0.000000
n的值为1091567616
*p的值为9.000000

为什么会出现上面这种情况呢?原因是在计算机中整型的存储和浮点型的存储是不一样的,所以会导致出现上面这种情况

浮点数在计算机内部的表示方法
根据国际标准IEEE754,任意一个二进制浮点数v可以表示成以下形式
(-1) ^ s* m * 2 ^ e
(-1) ^ s表示符号位,s=0时,v为正数;s=1时,v为负数
m表示有效数字,大于等于1,小于2
2 ^ e表示指数位
IEEE754规定,对于32位的浮点数,最高的1位是符号位s,接着的8位是指数e,剩下的23位为有效数字m
 由于m是大于等于1,小于2的,所以我们忽略1,直接将后面的23位全存储小数,拿出来之后再在加一个整数部分1,这样我们就可以保存24位有效数字了
IEEE754规定,对于64位的浮点数,最高的一位是符号位s,接着的11位是指数e,剩下的52位为有效数字m
e为一个无符号整数,如果e为8位,取值范围为0-255,如果是11位,取值范围为0-2047
由于科学计数法中的e是可以出现负数的,所以IEEE754规定,存入内存时e的真实值必须加上一个中间数,对于8位的e,这个中间数是127,对于11位的e,这个中间数是1023
比如:2^10的e

以9.0为例,9.0的二进制浮点数小数点前后分开表示,1001.0,                            

 0.5的二进制浮点数表示为0.1,因为小数点后的1为1*2^-1,0.01的十进制为0.25
1001.0--->(-1)^0*1.001*2^3--->(-1)^0*1.001*2^(3+127)--->(-1)^0*1.001*2^(130)          

0.1--->(-1)^0*1*2^(-1+127)--->(-1)^0*1*2^(126)
5.5           101.1                      (-1)^0*1.011*2^2
0 10000001 01100000000000000000000
      ↑129           ↑011为小数位,后面补齐至23位

e的取出
 e不为全0或不为全1:
   e转十进制,减去127(或1023),得到e的真实值,小数部分前加一个“1.”,
 e为全0:
   这时,指数e为1-127(或1-1023),有效数字m不再加上第一位的1,而是还原为0.xxxx,这样做是为了表示±0,以及接近于0的很小的数字
 e为全1:
   这时,表示无穷大,正负数取决于符号位 
 

int main()
{
	int n = 9;
	/*00000000000000000000000000001001原码(补码)*/
	float* p = (float*)&n;
	printf("n的值为%d\n", n);
	printf("*p的值为%f\n", *p);/*以浮点数角度看,00000000000000000000000000001001是(-1)^0*0.00000000000000000001001*2^-126,近似为0*/
	*p = 9.0;
	/*(-1)^0*1.001*2^3--->0 10000010 00100000000000000000000,从整型角度来看这就是一个二进制反码,又因为最高位为0,所以正数的原反补相同,所以这就是原码,从而输出十进制数*/
	printf("n的值为%d\n", n);
	printf("*p的值为%f\n", *p);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值