C语言---数据的存储

本文详细介绍了数据存储的不同类型,包括整型家族(如char、short、int等)和浮点型家族(如float、double),并深入探讨了它们在内存中的存储方式,特别是大小端模式、原码反码补码的概念以及浮点数遵循的IEEE存储规则。此外,通过实例展示了不同类型数据在内存中的存储形式和计算过程。
摘要由CSDN通过智能技术生成

目录

一、数据存储

二、数据存储类型分类

1、整型家族

2、浮点型家族

3、自定义类型

4、指针类型

5、空类型

三、整型家族在内存中的存储

1、大小端的理解

2、大小端直观内存显示图:

3、大小端存储的方式如何检测

4、整型家族内存中的存储方式

a、原码反码补码:    

b:数据在内存中的存储

 四、浮点型家族在内存中的存储

1、IEEE的存储规则

2、浮点数在内存中的存储

五、总结:


一、数据存储

基本数据类型

char            // 字符数据类型           1个字节
short           // 短整型                      2个字节
int               // 整形                          4个字节  
long            // 长整型                      4个字节  
long long    // 更长的整形               8个字节
float            // 单精度浮点数           4个字节
double        // 双精度浮点数           8个字节   

二、数据存储类型分类

1、整型家族

char :                          取值范围 
unsigned char              0~255
    signed char              -128~127
short:
unsigned short [ int ]      0~65,535
    signed short [ int ]      -32768~32,767
int:
unsigned int                  0~4,294,967,295
    signed int                  -2,147,483,648~2,147,483,647
long:
unsigned long [ int ]         0~4,294,967,295
    signed long [ int ]        -2,147,483,648~2,147,483,647

2、浮点型家族

float
double
long double

3、自定义类型

结构体类型                               struct  
枚举类型                                   enum
联合类型                                   union

4、指针类型

char*          

short*      
int*              
long*          
long long*   
float*          
double* 
struct* pc 
void*  

5、空类型

void     空类型(用于函数的返回类型、函数的参数、指针类型

三、整型家族在内存中的存储

1、大小端的理解

    数据是从低位向高位进行存储,但在数据的存储过程中,数据在从低位向高位的存放顺序不一,从而形成了两种数据存放的模式:大端模式和小端模式

大端(存储)模式:
    是指数据的低位字节内容保存在内存的高地址中,而数据的高位字节内容保存在内存的低地址中;
小端(存储)模式:
    是指数据的低位字节内容保存在内存的低地址中,而数据的高位字节内容保存在内存的高地址中。

2、大小端直观内存显示图:

3、大小端存储的方式如何检测

4、整型家族内存中的存储方式

    整型家族在内存中的存储是以补码的方式进行存储,再讲他们的存储之前先讲一下什么是原码反码补码。原码反码补码在32位机上是32比特位,在64机位上是64比特位。

a、原码反码补码:    

    ①原反补码中:第一位符号位,其余几位为数据值位。

     ②原码反码补码

正数的符号位为0,原码的数值位为该数,原码反码补码相同

负数的符号位为1,原码的数值位为该数,反码符号位不变数值位取反,补码为反码+1

   

    ③该知识为计算机组成原理中的相关知识,原码转换为补码总结为:

正数的原反补码相同,负数符号位不变。

补码为原码从右边数到第一个1位置不变,数值位往左到符号位后全部取反。

b:数据在内存中的存储

    ①实例一

int main()
{
	//整型家族
	//10000000 00000000 00000000 00010100   原码
	//11111111 11111111 11111111 11101100   补码
	//ff ff ff ec
	unsigned int i = -20;
	
	//00000000 00000000 00000000 00001010   原码
	//00000000 00000000 00000000 00001010   补码
	//00 00 00 0a
	int j = 10;
	

	printf("%d\n", i + j);//%d打印的是有符号的数
	//i+j
	// 补码相加
	//11111111 11111111 11111111 11101100   i
	//00000000 00000000 00000000 00001010   j
	//11111111 11111111 11111111 11110110   i+j补码
	//10000000 00000000 00000000 00001010   i+j原码
	//以有符号的形式打印就是补码转为原码(数据在内存中以补码存储,打印有符号数值时转为原码)
	//结果-10

	printf("%u\n", i + j);//%u打印的是无符号的数
	//i+j
	// 补码相加
	//11111111 11111111 11111111 11101100   i
	//00000000 00000000 00000000 00001010   j
	//11111111 11111111 11111111 11110110   i+j补码
	//以无符号的形式打印就是直接打印补码(首元素1不再表示符号位)
	//结果4294967286
    
    return 0;
}

     ②实例二

int main()
{
    //因为i是无符号数,所以在循环中一直是大于等于0,进入死循环
    unsigned int i;
	for(i = 9; i >= 0; i--)
		printf("%u\n",i);
}

     ③实例三

int main()
{
    //10000000 00000000 00000000 00000001 原码
	//11111111 11111111 11111111 11111111 补码
	//char类型只取1个字节,内存中存放ff(11111111)
    char a = -1;
	signed char b = -1;
	//a,b是有符号的char,%d输出时会整型提升前面补符号位1
	//11111111 11111111 11111111 11111111
	//转为原码为10000000 00000000 00000000 00000001打印为-1

    unsigned char c = -1;
	//c是无符号char,整型提升前面补0
	//00000000 00000000 00000000 11111111无需转为原码直接打印255
	printf("%d %d %d\n", a, b, c);
    return 0;
}

a,b,c内存中的存放

 运行结果

     ④实例四

int main()
{
    //128
	//00000000 00000000 00000000 10000000  原码
	//00000000 00000000 00000000 10000000  补码
	//存入内存10000000
	char a = 128;

	//-128
	//10000000 00000000 00000000 10000000 原码
	//11111111 11111111 11111111 10000000 补码
	//存入内存10000000
	char b = -128;

	//a整型提升为
	//11111111 11111111 11111111 10000000 补码
	//10000000 00000000 00000000 10000000 转为原码
	//以%d输出原码
	//以%u直接输出补码
	//  
	//b整型提升为
	//11111111 11111111 11111111 10000000 补码
	//10000000 00000000 00000000 10000000 转为原码
	//以%d输出原码
	//以%u直接输出补码
	printf("%d %d\n", a, b);
	printf("%u %u\n", a, b);

    return 0;
}

运行结果

 char类型在内存中的存储范围为-128~127,上图中char类型的128存入内存中相当于127+1=-128

     ⑤实例五

int main()
{ 
   char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
		//有符号char类型的取值范围是 -128~127
		//-1 -2 -3 -4 ... -128 127 126 ... 1 0
		//128 + 127 = 255
	}
	printf("%d", strlen(a));//'\0'结束
    return 0;
}

运行结果

 四、浮点型家族在内存中的存储

    1、IEEE的存储规则

在讲浮点型在内存中的存储前首先要了解什么是IEEE规则

IEEE 754 规定:

对于32位的单精度浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M

对于64位的双精度浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M

如图所示:
    32位:

     64位:

 根据国际标准IEEE754,任意一个二进制浮点数V可以表示成下面的形式:

(-1)^S * M * 2^E

(-1)^S: 表示符号位,当 S=0 V 为正数;当 S=1 V 为负数。
M: 表示有效数字,大于等于 1 ,小于 2
2^E: 表示指数位。
对于M来说:
IEEE 754 规定,在计算机内部保存 M 时,默认这个数的第一位是1,因此可以被舍去,只保存后面的部分,比如保存1.625时只保存625,取出来时,小数点前自动补1。 这样就可以节省一个比特位,增加精度。
32 位浮点数为例,留给M 只有 23位,将第一位的 1 舍去以后,等于可以保存 24 位有效数字,64位浮点数同样如此。
对于E来说:
E是一个无符号的整数
如果 E 8 位,它的取值范围为 0~255;
如果 E 11 位,它的取值范围为 0~2047
但是,我们知道,科学计数法中的E 是可以出现负数的,所以IEEE754 规定,存入内存时 E 的真实值前必须再加上一个中间数。
对于 8 位的 E ,这个中间数是127
对于 11 位的 E ,这个中间数是1023
比如, 2^13中 E 13 ,所以保存成 32 位浮点数时,必须保存成 13+127=140 ,即
10001100
但同时我们要考虑到,浮点数无限接近于0或趋于无穷大的情况。
当E为全0时,即真实值为-127( 或者-1023),2^-127(或者 -1023)是一个无限接近于0的数。
当E为全1时,即真实值为128( 或者1024),2^128(或者 1024)是一个趋于无穷大的数。

2、浮点数在内存中的存储

int main()
{
    //浮点型家族
	//9
	//00000000 00000000 00000000 00001001 原码反码补码相同
	int n = 9;
	float* pFloat = (float*)&n;
	//取原码00000000 00000000 00000000 00001001
	//以%d打印为9
	printf("n的值为: %d\n",n);

	//00000000 00000000 00000000 00001001 *pFloat得到的是这个,以%f的形式打印
	//0 00000000 00000000000000000001001
	//S = 0
	//E = 0(E为全0,是一个无限接近于0的数)
	//M = 1.000..
    //(-1)^S * M * 2^E 
    //(-1)^0 * 1.000 * 2^(-127) 
	//打印为0.000000
	printf("*pFloat的值为: %f\n",*pFloat);

	//9.0放在float类型中
	//9.0转化为二进制浮点数为
	//1001.0
	//转为科学计数法
	//1.001*2^3 
	//(-1)^S * M * 2^E 
	//S = 0 
	//E = 3+127 = 130 二进制为--->10000010
	//M = 00100000000000000000000
	//0 10000010 00100000000000000000000  IEE的存储E规则
	//01000001 00010000 00000000 00000000 在内存中的存储
	*pFloat = 9.0; 

    //01000001 00010000 00000000 00000000 
	//以%d打印是一个非常大的正数
	printf("n 的值为: %d\n",n);

	//以%f打印将
	//01000001 00010000 00000000 00000000用IEEE的转化规则转为
	//0 10000010 00100000000000000000000
	//S = 0 
	//E = 10000010 ---> 130-127 = 3
	//M = 00100000000000000000000
	//(-1)^S * M * 2^E
	//(-1)^0 * 1.001 * 2^3 = 9.0
	printf("*pFloat的值为: %f\n",*pFloat);

	return 0;
}

运行结果

五、总结:

本章详细讲解了整型家族和浮点型家族数据类型在内存中的存储方式,制作不易,希望对各位有帮助。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值